Java8 Stream API

Stream API是Java8中處理集合的關鍵組件循衰,提供了各種豐富的函數(shù)式操作。

Stream的創(chuàng)建

任何集合都可以轉(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的簡單使用

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();

收集結(jié)果

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類型

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

函數(shù)式接口

Steam.filter方法接受一個Predicate函數(shù)作為入?yún)ⅲ摵瘮?shù)返回一個boolean類型岂嗓,下圖為Stream和COllectors方法參數(shù)的函數(shù)式接口:

總結(jié)

Stream的處理總會在最后的Terminal操作才會真正執(zhí)行;

沒有內(nèi)部存儲汁展,也不能改變使用到的數(shù)據(jù)源,每次操作都會生成一個新的流厌殉;

并行流使用fork/join 池來實現(xiàn)食绿,對于非CPU密集型任務,需要謹慎使用公罕;

相對于循環(huán)遍歷操作代碼可讀性更高器紧;

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市楼眷,隨后出現(xiàn)的幾起案子铲汪,更是在濱河造成了極大的恐慌熊尉,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掌腰,死亡現(xiàn)場離奇詭異狰住,居然都是意外死亡,警方通過查閱死者的電腦和手機齿梁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門催植,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人勺择,你說我怎么就攤上這事创南。” “怎么了省核?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵稿辙,是天一觀的道長。 經(jīng)常有香客問我气忠,道長邻储,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任笔刹,我火速辦了婚禮芥备,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舌菜。我一直安慰自己萌壳,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布日月。 她就那樣靜靜地躺著袱瓮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪爱咬。 梳的紋絲不亂的頭發(fā)上尺借,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音精拟,去河邊找鬼燎斩。 笑死,一個胖子當著我的面吹牛蜂绎,可吹牛的內(nèi)容都是我干的栅表。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼师枣,長吁一口氣:“原來是場噩夢啊……” “哼怪瓶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起践美,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤洗贰,失蹤者是張志新(化名)和其女友劉穎找岖,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敛滋,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡许布,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绎晃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爹脾。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖箕昭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情解阅,我是刑警寧澤落竹,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站货抄,受9級特大地震影響述召,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蟹地,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一积暖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怪与,春花似錦夺刑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至耘斩,卻和暖如春沼填,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背括授。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工坞笙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人荚虚。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓薛夜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親曲管。 傳聞我的和親對象是個殘疾皇子却邓,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 了解Stream ? Java8中有兩個最為重要的改變,一個是Lambda表達式院水,另一個就是Stream AP...
    龍歷旗閱讀 3,318評論 3 4
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,454評論 0 13
  • Int Double Long 設置特定的stream類型腊徙, 提高性能简十,增加特定的函數(shù) 無存儲。stream不是一...
    patrick002閱讀 1,273評論 0 0
  • Java8 Stream-API Stream 流類似集合類中的Iterator撬腾,但是比Iterator高級螟蝙,只需...
    Mrsimple_4f84閱讀 485評論 0 1
  • 先看一段代碼 Stream API的歷史 在java8引入 受益于lambda表達式 lambda表達式 接口常被...
    ThomasYoungK閱讀 631評論 0 0