亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

Java函數式編程(十):收集器

2019-11-26 15:24:23
字體:
來源:轉載
供稿:網友

前面我們已經用過幾次collect()方法來將Stream返回的元素拼成ArrayList了。這是一個reduce操作,它對于將一個集合轉化成另一種類型(通常是一個可變的集合)非常有用。collect()函數,如果和Collectors工具類里的一些方法結合起來使用的話,能提供極大的便利性,本節我們將會介紹到。

我們還是繼續使用前面的Person列表作為例子,來看一下collect()方法到底有哪些能耐。假設我們要從原始列表中找出所有大于20歲的人。下面是使用了可變性和forEach()方法實現的版本:

復制代碼 代碼如下:

List<Person> olderThan20 = new ArrayList<>(); people.stream()
        .filter(person -> person.getAge() > 20)
.forEach(person -> olderThan20.add(person)); System.out.println("People older than 20: " + olderThan20);

我們使用filter()方法來從列表中過濾出了所有年齡大于20的人。然后,在forEach方法里,我們將元素添加到一個在前面已經初始化好的ArrayList中。我們先看下這段代碼的輸出結果,一會兒再去重構它。

復制代碼 代碼如下:

People older than 20: [Sara - 21, Jane - 21, Greg - 35]

程序輸出的結果是對的,不過還有點小問題。首先,把元素添加到集合中,這種屬于低級操作――它是命令式的,而非聲明式的。如果我們想把這個迭代改造成并發的,還得去考慮線程安全的問題――可變性使得它難以并行化。幸運的是,使用collect()方法可以很容易解決掉這個問題。來看下如何實現的。

collect()方法接受一個Stream并將它們收集到一個結果容器中。要完成這個工作,它需要知道三個東西:

+如何創建結果容器(比如說,使用ArrayList::new方法) +如何把單個元素添加到容器中(比如使用ArrayList::add方法) +如何把一個結果集合并到另一個中(比如使用ArrayList::addAll方法)

對于串行操作而言,最后一條不是必需的;代碼設計的目標是能同時支持串行和并行的。

我們把這些操作提供給collect方法,讓它來把過濾后的流給收集起來。

復制代碼 代碼如下:

List<Person> olderThan20 =
people.stream()
.filter(person -> person.getAge() > 20)
.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
System.out.println("People older than 20: " + olderThan20);

這段代碼的結果和前面一樣,不過這樣寫有諸多好處。

首先,我們編程的方式更聚焦了,表述性也更強,清晰的傳達了你要把結果收集到一個ArrayList里去的目的。collect()的第一個參數是一工廠或者生產者,后面的參數是一個用來收集元素的操作。

第二,由于我們沒有在代碼中個執行顯式的修改操作,可以很容易并行地執行這個迭代。我們讓底層庫來完成修改操作,它自己會處理好協作及線程安全的問題,盡管ArrayList本身不是線程安全的――干的漂亮。

如果條件允許的話,collect()方法可以并行地將元素添加到不同的子列表中,然后再用一個線程安全的方式將它們合并到一個大列表里(最后一個參數就是用來進行合并操作的)。

我們已經看到,相對于手動把元素添加到列表而言,使用collect()方法的好處真是太多了。下面我們來看下這個方法的一個重載的版本――它更簡單也更方便――它是使用一個Collector作為參數。這個Collector是一個包含了生產者,添加器,以及合并器在內的接口――在前面的版本中這些操作是作為獨立的參數分別傳入方法中的――使用Collector則更簡單并且可以復用。Collectors工具類提供了一個toList方法,可以生成一個Collector的實現,用來把元素添加到ArrayList中。我們來修改下前面那段代碼,使用一下這個collect()方法。

復制代碼 代碼如下:

List<Person> olderThan20 =
people.stream()
.filter(person -> person.getAge() > 20)
.collect(Collectors.toList());
System.out.println("People older than 20: " + olderThan20);

使用了Collectors工具類的簡潔版的collect()方法,可不止這一種用法。Collectors工具類中還有好幾種不同的方法來可以進行不同的收集和添加的操作。比如說,除了toList()方法,還有toSet()方法,可以添加到一個Set中,toMap()方法可以用來收集到一個key-value的集合中,還有joining()方法,可以拼接成一個字符串。我們還可以將mapping(),collectingAndThen(),minBy(), maxBy()和groupingBy()等方法組合起來進行使用。

我們來用下groupingBy()方法來將人群按年齡進行分組。

復制代碼 代碼如下:

Map<Integer, List<Person>> peopleByAge =
people.stream()
.collect(Collectors.groupingBy(Person::getAge));
System.out.println("Grouped by age: " + peopleByAge);

只需簡單的調用下collect()方法便能完成分組。groupingBy()接受一個lambda表達式或者方法引用――這種叫分類函數――它返回需要分組的對象的某個屬性的值。根據我們這個函數返回的值,來把調用上下文中的元素放進某個分組中。在輸出中可以看到分組的結果:

復制代碼 代碼如下:

Grouped by age: {35=[Greg - 35], 20=[John - 20], 21=[Sara - 21, Jane - 21]}

這些人已經按年齡進行了分組。

在前面這個例子中我們按人群的年齡對他們進行了分組收集。groupingBy()方法的一個變種可以按多個條件進行分組。簡單的groupingBy()方法使用了分類器進行元素收集。而通用的groupingBy()收集器,則可以為每一個分組指定一個收集器。也就是說,元素在收集的過程中會途經不同的分類器和集合,下面我們將會看到。

繼續使用上面這個例子,這回我們不按年齡分組了,我們只獲取人的名字,按他們的年齡進行排序。

復制代碼 代碼如下:

Map<Integer, List<String>> nameOfPeopleByAge =
people.stream()
.collect(
groupingBy(Person::getAge, mapping(Person::getName, toList())));
System.out.println("People grouped by age: " + nameOfPeopleByAge);

這個版本的groupingBy()接受兩個參數:第一個是年齡,這是分組的條件,第二個是一個收集器,它是由mapping()函數返回的結果。這些方法都來自Collectors工具類,在這段代碼中進行了靜態的導入。mapping()方法接受兩個參數,一個是映射用的屬性,一個是對象要收集到的地方,比如說list或者set。來看下上面這段代碼的輸出結果:

復制代碼 代碼如下:

People grouped by age: {35=[Greg], 20=[John], 21=[Sara, Jane]}

可以看到,人們的名字已經按年齡進行分組了。

我們再來看一個組合的操作:按名字的首字母進行分組,然后選出每個分組中年紀最大的那位。

復制代碼 代碼如下:

Comparator<Person> byAge = Comparator.comparing(Person::getAge);
Map<Character, Optional<Person>> oldestPersonOfEachLetter =
people.stream()
.collect(groupingBy(person -> person.getName().charAt(0),
reducing(BinaryOperator.maxBy(byAge))));
System.out.println("Oldest person of each letter:");
System.out.println(oldestPersonOfEachLetter);

我們先是按名字的首字母進行了排序。為了實現這個,我們把一個lambda表達式作為groupingBy()的第一個參數傳了進去。這個lambda表達式是用來返回名字的首字母的,以便進行分組。第二個參數不再是mapping()了,而是執行了一個reduce操作。在每個分組內,它使用maxBy()方法,從所有元素中遞推出最年長的那位。由于組合了許多操作,這個語法看起來有點臃腫,不過整個讀起來是這樣的:按名字首字母進行分組,然后遞推出分組中最年長的那位。來看下這段代碼的輸出,它列出了指定字母開頭的那組名字中年紀最大的那個人。

復制代碼 代碼如下:

Oldest person of each letter:
{S=Optional[Sara - 21], G=Optional[Greg - 35], J=Optional[Jane - 21]}

我們已經領教到了collect()方法以及Collectors工具類的威力。在你的IDE或者JDK的官方文檔里面,再花點時間去研究下Collectors工具類吧,熟悉下它提供的各種方法。下面我們將會用lambda表達式來完成一些過濾器的實現。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
懂色aⅴ精品一区二区三区蜜月| 色www亚洲国产张柏芝| 日韩成人网免费视频| 国产精品91一区| 国产日韩欧美夫妻视频在线观看| 国产精品爱啪在线线免费观看| 欧美午夜久久久| 国产精品一区二区三区成人| 国产一区香蕉久久| 久久精品人人做人人爽| 欧美精品一区二区三区国产精品| 久久久亚洲国产天美传媒修理工| 91九色综合久久| 久久九九全国免费精品观看| 欧美激情欧美激情在线五月| 91av视频导航| 欧美黑人巨大精品一区二区| 欧美日韩免费网站| 亚洲欧洲黄色网| 国产精品美女www| 国产99久久精品一区二区 夜夜躁日日躁| 日韩综合视频在线观看| 国产精品免费一区二区三区都可以| 亚洲国产中文字幕在线观看| 亚洲成人av在线播放| 91免费的视频在线播放| 欧美激情在线视频二区| 91香蕉国产在线观看| 欧洲永久精品大片ww免费漫画| 91九色国产社区在线观看| 91免费在线视频| 中文字幕亚洲欧美| 91久久久久久久久久久久久| 伊人精品在线观看| 日产精品久久久一区二区福利| 亚洲图片在线综合| 国产精品高清在线观看| 亚洲第一级黄色片| 欧美日韩在线一区| 亚洲精品在线观看www| 91久久嫩草影院一区二区| 欧美色视频日本高清在线观看| 国产欧美日韩精品专区| 日韩av免费在线播放| 美女扒开尿口让男人操亚洲视频网站| 尤物yw午夜国产精品视频明星| 国产成人精品一区| 国产精品直播网红| 日韩成人av网| 成人网在线观看| 不卡av在线播放| 日韩暖暖在线视频| 欧美日韩在线看| 亚洲欧美综合另类中字| 热久久这里只有| 精品日韩中文字幕| 国产999精品久久久| 国产精品久久久久免费a∨大胸| 大荫蒂欧美视频另类xxxx| 韩国日本不卡在线| 日韩av毛片网| 国内成人精品视频| 91精品视频免费| 日韩美女免费线视频| 51精品在线观看| 96pao国产成视频永久免费| 92国产精品久久久久首页| 色综合色综合久久综合频道88| 日韩免费av在线| 国产精品成人v| 国产精品免费看久久久香蕉| 日韩欧美在线观看视频| 欧美激情xxxx| 日韩免费观看在线观看| 免费91在线视频| 高清在线视频日韩欧美| 日韩女优人人人人射在线视频| 国产精品视频地址| 日韩av在线一区二区| 亚洲成人av在线播放| 亚洲黄色在线看| 日韩风俗一区 二区| 成人性教育视频在线观看| 亚洲欧美福利视频| 国产日韩欧美在线看| 日韩欧美成人免费视频| 国产精品久久久久av| 欧美成人午夜免费视在线看片| 国产成人97精品免费看片| 77777少妇光屁股久久一区| 欧美视频免费在线观看| 影音先锋欧美在线资源| 亚洲精品视频中文字幕| 国产精品大陆在线观看| 欧美激情亚洲一区| 国产精品99久久久久久白浆小说| 日韩在线视频网| 国产精品一区电影| 精品美女永久免费视频| 亚洲美女动态图120秒| 黑人巨大精品欧美一区二区三区| 日韩小视频在线观看| 日本欧美在线视频| 亚洲人成伊人成综合网久久久| 日韩成人在线电影网| 色一情一乱一区二区| 亚洲日本欧美中文幕| 欧美精品在线免费| 91chinesevideo永久地址| 久久久免费高清电视剧观看| 91免费国产视频| 国产日韩在线免费| 国产精品一二三在线| 国产精品mp4| 高清一区二区三区日本久| 亚洲色图13p| 亚洲成人动漫在线播放| 欧美日韩人人澡狠狠躁视频| 在线看国产精品| 久久99精品久久久久久青青91| 综合网日日天干夜夜久久| 国产精品观看在线亚洲人成网| 亚洲高清不卡av| 亚洲国产精品国自产拍av秋霞| 欧美大片在线看免费观看| 日本成人在线视频网址| 亚洲香蕉在线观看| 欧美日韩激情视频| 色综合久久悠悠| 久久综合九色九九| 91久久国产精品| 91日本视频在线| 日韩少妇与小伙激情| 欧美性少妇18aaaa视频| 欧美激情成人在线视频| 亚洲日韩中文字幕在线播放| 亚洲综合色激情五月| 亚洲人成网站777色婷婷| 久久这里有精品视频| 91精品国产91久久久久久| 668精品在线视频| 亚洲人成电影在线播放| 欧美性xxxx极品hd满灌| 成人久久18免费网站图片| 久久亚洲综合国产精品99麻豆精品福利| 日韩中文在线观看| 91精品综合视频| 最新91在线视频| 国产剧情久久久久久| 久久久中精品2020中文| 亚洲精品综合久久中文字幕| 欧美日韩999| 亚洲精品91美女久久久久久久| 黑丝美女久久久| 欧美激情精品久久久久| 日韩成人中文字幕在线观看| 最近2019中文免费高清视频观看www99| 成人做爰www免费看视频网站| 欧美大片在线看| 国产日韩欧美另类| 久久精品国产欧美激情| 国产精品一区二区三区毛片淫片| 久久久久久久av| 亚洲欧美日韩图片|