一、迭代
public static void main(String[] args) {
int[] nums = {1, 2, 3};
//外部迭代
int sum = 0;
for (int i: nums){
sum += i;
}
//內(nèi)部迭代
int sum2 = IntStream.of(nums).sum();
System.out.println(sum == sum2);
}
- 中間操作:返回Stream
- 終止操作:返回最終結(jié)果
惰性求值:若沒有執(zhí)行終止操作,則中間操作不會執(zhí)行兰绣。
流只能遍歷一次弦追。
二、流的創(chuàng)建
public class Test {
public static void main(String[] args) {
//從集合創(chuàng)建
List list = new ArrayList();
list.stream();
//從數(shù)組創(chuàng)建
Arrays.stream(new int[]{1, 2, 3});
//創(chuàng)建數(shù)字流
IntStream.of(1, 2, 3);
IntStream.rangeClosed(1, 10);
//使用Random創(chuàng)建無限流
new Random().ints().limit(10);
//自己創(chuàng)建
Random random = new Random();
Stream.generate(() -> random.nextInt(10)).limit(10);
try(Stream<String> lines = Files.lines(Paths.get(""))){
//由文件生成流
}catch (IOException e){
//顯式捕獲流中的異常
}
}
}
對象流和數(shù)值流的轉(zhuǎn)化:
- 映射到數(shù)值流:mapToInt、mapToDouble寝蹈、mapToLong返回一個數(shù)值流IntStream慧域、DoubleStream榆骚、LongStream片拍。
- 轉(zhuǎn)換回對象流:使用boxed()方法,如intStream.boxed()轉(zhuǎn)化為Stream<Integer>類型妓肢。
三捌省、中間操作
- map:映射,對值進(jìn)行處理碉钠。
- flatMap:多個stream連成一個stream纲缓。
- filter:過濾,保留通過某項測試的對象放钦。
- peak:用于debug,是個中間操作色徘,類似foreach。
- limit:返回一個不超過給定長度的流操禀。有狀態(tài)-有界褂策。
- skip:跳過前n個元素,若元素不足n個颓屑,返回一個空流斤寂。有狀態(tài)-有界。
- sorted:排序揪惦。有狀態(tài)-無界遍搞。
- distinct:返回一個元素各異的流。(根據(jù)流所生成的元素的hashCode和equal方法實現(xiàn))器腋。有狀態(tài)-無界溪猿。
- peek:將中間變量的值輸出到日志中。
tips:filter和map一起使用時纫塌,盡管它們是兩個獨立的操作诊县,但它們會被合并到同一次遍歷中,這種技術(shù)叫做循環(huán)合并措左。
有狀態(tài)操作:需要知道先前的歷史依痊。
四、終止操作
- collect:收集到集合怎披。
- reduce:把流合成一個對象胸嘁。有狀態(tài)-有界。
- foreach:消費流中的每個元素凉逛,返回void性宏。
- count:返回流中元素的個數(shù)。
- allMatch状飞、anyMatch毫胜、noneMatch蝌借、findFirst、findAny
- min指蚁、max
public class Test {
public static void main(String[] args) {
String str = "hello world";
List<Character> list = Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed()).map(c -> (char)c.intValue()).collect(Collectors.toList());
System.out.println(list);
//帶初始值的reduce
Integer len = Stream.of(str.split(" "))
.map(s -> s.length())
.reduce(0, (s1, s2) -> s1+s2);
System.out.println(len);
}
}
五、收集器
將流元素歸約和匯總為一個值
(1)Collectors.toList()自晰、Collectors.toSet()凝化、Collectors.toCollection(TreeSet::new),將流轉(zhuǎn)化為集合酬荞。
(2)counting()搓劫、minBy()、maxBy()混巧、averagingXX()枪向、summarizingXX(),對流進(jìn)行統(tǒng)計個數(shù)咧党、最小值秘蛔、最大值、平均數(shù)傍衡、匯總等操作深员。
(3)joining()對流中的每個對象的toString()得到的字符串連接成一個字符串。
(4)reducing(初始值,轉(zhuǎn)換函數(shù),累積函數(shù))蛙埂,轉(zhuǎn)換函數(shù)的類型為BiFunction<T,T,T>倦畅,reducing()方法是上述這些特殊情況的一般化。元素分組
(1)groupingBy(?)返回一個Map<T, List<T>>
(2)多級分組:groupingBy(?, groupingBy(?))
(3)可搭配其他收集器使用:groupingBy(?, counting())绣的、groupingBy(?叠赐,mapping() )
(4)mapping(映射函數(shù),收集成集合)。
(5)collectingAndThen(要轉(zhuǎn)換的收集器,轉(zhuǎn)換函數(shù))屡江,將收集器的結(jié)果轉(zhuǎn)化為另一種類型芭概。元素分區(qū)
partitioningBy(?) 返回一個Map<Boolean, List<T>>
可類比groupingBy()的用法自定義收集器
(1)Collector接口解析
/**
* 前四個方法都會返回一個被collect方法調(diào)用的函數(shù)
* 第五個方法提供了一個提示列表,告訴collect方法在執(zhí)行歸約操作時可以應(yīng)用哪些優(yōu)化
* @param <T>集合中要收集的項目的泛型
* @param <A>累加器的類型盼理,累加器是在收集過程用于累積部分結(jié)果的對象
* @param <R>收集操作得到的對象
*/
interface Collector<T, A, R> {
/**
* 建立新的結(jié)果容器
* @return
*/
Supplier<A> supplier();
/**
* 將元素添加到結(jié)果容器
* @return
*/
BiConsumer<A, T> accumulator();
/**
* 對結(jié)果容器應(yīng)用最終轉(zhuǎn)換
* @return
*/
Function<A, R> finisher();
/**
* 合并兩個結(jié)果容器
* @return
*/
BinaryOperator<A> combiner();
/**
*Characteristics是一個包含CONCURRENT谈山、UNORDERED、IDENTITY_FINISH三個項目的枚舉類
*CONCURRENT accumulator函數(shù)可以從多個線程同時調(diào)用宏怔,且收集器可以并行歸約流奏路。如果沒有聲明為UNORDERED,僅在無序數(shù)據(jù)源才可以并行歸約
* UNORDERED歸約結(jié)果不受流中項目遍歷和累積順序的影響
* IDENTITY_FINISH表明完成器方法返回的函數(shù)是一個恒等函數(shù)臊诊。這種情況下鸽粉,累加器對象將會直接用作歸約過程的最終結(jié)果
* @return
*/
Set<Characteristics> characteristics();
}
(2)自定義收集器:模擬toList()
public class TestDemo {
public static void main(String[] args) {
System.out.println(IntStream.rangeClosed(0, 100).boxed().collect(new ToListCollector<>()));
}
}
class ToListCollector<T> implements Collector<T, List<T>, List<T>> {
/**
* 創(chuàng)建一個空的容器
* @return
*/
@Override
public Supplier<List<T>> supplier() {
return ArrayList::new;
}
/**
* 加元素添加到容器中
* @return
*/
@Override
public BiConsumer<List<T>, T> accumulator() {
return List::add;
}
/**
* 恒等函數(shù)
* @return
*/
@Override
public Function<List<T>, List<T>> finisher() {
return Function.identity();
}
/**
* 將兩個累加器合并并返回
* @return
*/
@Override
public BinaryOperator<List<T>> combiner() {
return (list1, list2) -> {
list1.addAll(list2);
return list1;
};
}
/**
* 為收集器添加IDENTITY_FINISH和CONCURRENT標(biāo)志
* @return
*/
@Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(java.util.stream.Collector.Characteristics.IDENTITY_FINISH, java.util.stream.Collector.Characteristics.CONCURRENT));
}
}
(3)自定義收集器:篩選質(zhì)數(shù)
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.IntStream;
/**
* @description: ${todo}
* @author: wxz1997
* @date: 18-9-26 下午7:50
*/
public class TestCollector{
public static void main(String[] args) {
System.out.println(IntStream.rangeClosed(2, 100).boxed().collect(new PrimeNumbersCollector()));
}
}
class PrimeNumbersCollector implements Collector<Integer, Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> {
//創(chuàng)建一個HashMap容器,含有兩個空的List
@Override
public Supplier<Map<Boolean, List<Integer>>> supplier() {
return () -> new HashMap<Boolean, List<Integer>>(){{
put(true, new ArrayList<>());
put(false, new ArrayList<>());
}};
}
@Override
public BiConsumer<Map<Boolean, List<Integer>>, Integer> accumulator() {
return (Map<Boolean, List<Integer>> acc, Integer candidate) -> {
acc.get(isPrime(acc.get(true), candidate)).add(candidate);
};
}
private static boolean isPrime(List<Integer> primes, Integer candidate) {
int candidateRoot = (int)Math.sqrt((double)candidate);
return takeWhile(primes, i -> i <= candidateRoot)
.stream()
.noneMatch(p -> candidate % p == 0);
}
private static <A> List<A> takeWhile(List<A> list, Predicate<A> p){
int i=0;
for (A item: list){
if (!p.test(item)){
return list.subList(0, i);
}
i++;
}
return list;
}
@Override
public Function<Map<Boolean, List<Integer>>, Map<Boolean, List<Integer>>> finisher() {
return Function.identity();
}
@Override
public BinaryOperator<Map<Boolean, List<Integer>>> combiner() {
return (Map<Boolean, List<Integer>> map1, Map<Boolean, List<Integer>> map2) -> {
map1.get(true).addAll(map2.get(true));
map1.get(false).addAll(map2.get(false));
return map1;
};
}
@Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(java.util.stream.Collector.Characteristics.IDENTITY_FINISH));
}
}
六抓艳、并行流
- 并行標(biāo)志parallel()触机,串行標(biāo)志sequential(),若多次使用,以最后一個為準(zhǔn)決定該流為串行還是并行儡首。
- 并行流內(nèi)部使用了默認(rèn)的ForkJoinPool片任,它默認(rèn)的線程數(shù)量為處理器的數(shù)量。
-
自動裝箱和拆箱操作會大大降低性能蔬胯,盡可能使用原始類型流IntStream对供、LongStream、DoubleStream等來避免這些操作氛濒。
根據(jù)可分解性判斷其是否適合并行
流的數(shù)據(jù)源和可分解性.png - 工作竊炔 :每個線程都為分配給它的任務(wù)保存一個雙向鏈?zhǔn)疥犃?每完成一個任務(wù),就會從隊列頭上取出下一個任務(wù)開始執(zhí)行∥韪停基于前面所述的原因,某個線程可能早早完成了分配給它的所有任務(wù),也就是它的隊列已經(jīng)空了,而其他的線程還很忙京景。這時,這個線程并沒有閑下來,而是隨機選了一個別的線程,從隊列的尾巴上“偷走”一個任務(wù)。這個過程一直繼續(xù)下去,直到所有的任務(wù)都執(zhí)行完畢,所有的隊列都清空骗奖。這就是為什么要劃成許多小任務(wù)而不是少數(shù)幾個大任務(wù),這有助于更好地在工作線程之間平衡負(fù)載确徙。