Stream API是Java8中處理集合的關鍵組件循衰,提供了各種豐富的函數(shù)式操作。
任何集合都可以轉(zhuǎn)換為Stream:
//數(shù)組
String[] strArr =newString[]{"aa","bb","cc"};
Stream streamArr = Stream.of(strArr);
Stream streamArr2 = Arrays.stream(strArr);
//集合
List list =newArrayList<>();
Stream streamList = list.stream();
Stream streamList2 = list.parallelStream();
//并行執(zhí)行...//generator 生成無限長度的
streamStream.generate(Math::random);
// iterate 也是生成無限長度的Stream,其元素的生成是重復對給定的種子值調(diào)用函數(shù)來生成的Stream.iterate(1, item -> item +1)
Stream的使用分為兩種類型:
Intermediate,一個Stream可以調(diào)用0到多個Intermediate類型操作幸逆,每次調(diào)用會對Stream做一定的處理,返回一個新的Stream假残,這類操作都是惰性化的(lazy)米间,就是說,并沒有真正開始流的遍歷栅隐。
常用操作:map (mapToInt, flatMap 等)塔嬉、 filter玩徊、 distinct、 sorted谨究、 peek恩袱、 limit、 skip胶哲、 parallel
Terminal,一個Stream只能執(zhí)行一次terminal 操作畔塔,而且只能是最后一個操作,執(zhí)行terminal操作之后鸯屿,Stream就被消費掉了澈吨,并且產(chǎn)生一個結(jié)果。
常用操作:forEach碾盟、 forEachOrdered棚辽、 toArray、 reduce冰肴、 collect屈藐、 min、 max熙尉、 count联逻、 anyMatch、 allMatch检痰、 noneMatch包归、 findFirst、 findAny
使用示例:
//filter 過濾操作
streamArr.filter(str->str.startsWith("a"));
//map 遍歷和轉(zhuǎn)換操作
streamArr.map(String::toLowerCase);
//flatMap 將流展開
Listlist1=newArrayList<>();
list1.add("aa");list1.add("bb");
Listlist2=newArrayList<>();
list2.add("cc");
list2.add("dd");
Stream.of(list1,list2).flatMap(str->str.stream()).collect(Collectors.toList());
//limit 提取子流
streamArr.limit(1);
//skip 跳過
streamArr.skip(1);
//peek 產(chǎn)生相同的流铅歼,支持每個元素調(diào)用一個函數(shù)
streamArr.peek(str->System.out.println("item:"+str));
//distinct 去重
Stream.of("aa","bb","aa").distinct();
//sorted 排序Stream.of("aaa","bb","c").sorted(Comparator.comparing(String::length).reversed());
//parallel 轉(zhuǎn)為并行流,謹慎使用
streamArr.parallel();
//forEach
streamArr.forEach(System.out::println);
//forEachOrdered 如果希望順序執(zhí)行并行流公壤,請使用該方法streamArr.parallel().forEachOrdered(System.out::println);
//toArray 收集到數(shù)組中
streamArr.filter(str->str.startsWith("a")).toArray(String[]::new);
//reduce 聚合操作
streamArr.reduce((str1,str2) -> str1+str2);
//collect收集到List中
streamArr.collect(Collectors.toList());
//collect收集到Set中
streamArr.collect(Collectors.toSet());
//min取最小值
IntStream.of(1,2,3,4).min();
Stream.of(arr).min(String::compareTo);
//max取最大值
IntStream.of(1,2,3,4).max();
Stream.of(arr).max(String::compareTo);
//count計算總量
streamArr.count();
//anyMatch判斷流中是否含有匹配元素
boolean hasMatch = streamArr.anyMatch(str -> str.startsWith("a"));
//allMatch判斷流中是否全部匹配
boolean hasMatch = streamArr.allMatch(str -> str.startsWith("a"));
//noneMatch判斷流中是否全部不匹配
boolean hasMatch = streamArr.noneMatch(str -> str.startsWith("a"));
//findFirst找到第一個就返回
streamArr.filter(str -> str.startsWith("a")).findFirst();
//findAny找到任意一個就返回
streamArr.filter(str -> str.startsWith("a")).findAny();
collect操作主要用于將stream中的元素收集到一個集合容器中,collect函數(shù)的定義如下:
R collect(Suppliersupplier,
BiConsumeraccumulator,
BiConsumercombiner);
第一個參數(shù)Supplier用于生成一個目標集合容器類型的實例椎椰;
函數(shù)BiConsumer
Set result = Stream.of("aa","bb","cc","aa").collect(
? ? ? ?() -> newHashSet(),
? ? ? ?(set, item)->set.add(item),
? ? ? ?(set, subSet)->set.addAll(subSet));
以上寫法可以使用操作符“::”簡化厦幅,語法如下:
對象::實例方法
類::靜態(tài)方法
類::實例方法
Set?result=Stream.of("aa","bb","cc","aa").collect(?
? ? ? ? ? ? HashSet::new,? ??
? ? ? ? ? ? HashSet::add,??
? ? ? ? ? ? HashSet::addAll);
Java.util.stream.Collectors類中已經(jīng)預定義好了toList,toSet慨飘,toMap确憨,toCollection等方便使用的方法,所以以上代碼還可以簡化如下:
Set result2 = Stream.of("aa","bb","cc","aa").collect(Collectors.toSet());
將結(jié)果收集到Map中瓤的,Collectors.toMap方法的兩個重載定義如下:
keyMapper函數(shù)用于從實例T中得到一個K類型的Map key;
valueMapper函數(shù)用于從實例T中得到一個U類型的Map value;
mergeFunction函數(shù)用于處理key沖突的情況休弃,默認為throwingMerger(),拋出IllegalStateException異常;
mapSupplier函數(shù)用于生成一個Map實例圈膏;
publicstatic? ? Collector> toMap(Function keyMapper,? ? ? ? ?
? ? ? ?Function valueMapper) {returntoMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);? ? }
publicstatic>? ? Collector toMap(Function keyMapper,? ? ? ? ? ? ? ? ? ? ? ? ?
?? ? ? Function valueMapper,? ? ? ? ? ? ? ? ? ? ? ? ? ?
?? ? BinaryOperator mergeFunction,? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? Supplier mapSupplier) {? ??
? ? BiConsumer accumulator? ? ? ? ? ? ? ? = (map, element) -> map.merge(keyMapper.apply(element),? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? valueMapper.apply(element), mergeFunction);
returnnewCollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);??
? }
假設有一個User實體類塔猾,有方法getId(),getName(),getAge()等方法,現(xiàn)在想要將User類型的流收集到一個Map中稽坤,示例如下:
Stream?userStream=Stream.of(newUser(0,"張三",18),newUser(1,"張四",19),newUser(2,"張五",19),newUser(3,"老張",50));
Map?userMap=userSteam.collect(Collectors.toMap(User::getId, item->item));
假設要得到按年齡分組的Map>,可以按這樣寫:
Map>ageMap=userStream.collect(Collectors.toMap(User::getAge, Collections::singletonList, (a, b)->{ListresultList=newArrayList<>(a);? ? ? ? ? ? resultList.addAll(b);returnresultList;? ? ? ? }));
這種寫法雖然可以實現(xiàn)分組功能桥帆,但是太過繁瑣医增,好在Collectors中提供了groupingBy方法,可以用來實現(xiàn)該功能老虫,簡化后寫法如下:
Map>ageMap2=userStream.collect(Collectors.groupingBy(User::getAge));
1
1
類似的,Collectors中還提供了partitioningBy方法茫多,接受一個Predicate函數(shù)祈匙,該函數(shù)返回boolean值,用于將內(nèi)容分為兩組天揖。假設User實體中包含性別信息getSex()夺欲,可以按如下寫法將userStream按性別分組:
Map> sexMap = userStream.collect(Collectors.partitioningBy(item -> item.getSex() >0));
1
1
Collectors中還提供了一些對分組后的元素進行downStream處理的方法:
counting方法返回所收集元素的總數(shù);
summing方法會對元素求和今膊;
maxBy和minBy會接受一個比較器些阅,求最大值,最小值斑唬;
mapping函數(shù)會應用到downstream結(jié)果上市埋,并需要和其他函數(shù)配合使用;
MapsexCount=userStream.collect(Collectors.groupingBy(User::getSex,Collectors.counting()));MapageCount=userStream.collect(Collectors.groupingBy(User::getSex,Collectors.summingInt(User::getAge)));Map>ageMax=userStream.collect(Collectors.groupingBy(User::getSex,Collectors.maxBy(Comparator.comparing(User::getAge))));Map>nameMap=userStream.collect(Collectors.groupingBy(User::getSex,Collectors.mapping(User::getName,Collectors.toList())));
1
2
3
4
5
6
7
1
2
3
4
5
6
7
以上為各種collectors操作的使用案例恕刘。
Optional 是對T類型對象的封裝缤谎,它不會返回null,因而使用起來更加安全褐着。
ifPresent方法接受一個函數(shù)作為形參坷澡,如果存在當前Optinal存在值則使用當前值調(diào)用函數(shù),否則不做任何操作含蓉,示例如下:
Optional optional =...optional.ifPresent(v -> results.add(v));
1
2
1
2
orElse方法频敛,orElseGet方法,當值不存在時產(chǎn)生一個替代值馅扣,示例如下:
Stringresult =optional.orElse("defaultValue");Stringresult =optional.orElseGet(() -> getDefalutValue());
1
2
1
2
可以使用Optional.of()方法和Optional.empty()方法來創(chuàng)建一個Optional類型對象斟赚,示例如下:
a - b >0?Optional.of(a - b) :Optional.empty();
1
1
Steam.filter方法接受一個Predicate函數(shù)作為入?yún)ⅲ摵瘮?shù)返回一個boolean類型岂嗓,下圖為Stream和COllectors方法參數(shù)的函數(shù)式接口:
Stream的處理總會在最后的Terminal操作才會真正執(zhí)行;
沒有內(nèi)部存儲汁展,也不能改變使用到的數(shù)據(jù)源,每次操作都會生成一個新的流厌殉;
并行流使用fork/join 池來實現(xiàn)食绿,對于非CPU密集型任務,需要謹慎使用公罕;
相對于循環(huán)遍歷操作代碼可讀性更高器紧;