溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JDK1.8新特性Stream的功能介紹

發(fā)布時(shí)間:2021-06-23 10:00:07 來源:億速云 閱讀:146 作者:chen 欄目:編程語言

這篇文章主要講解了“JDK1.8新特性Stream的功能介紹”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JDK1.8新特性Stream的功能介紹”吧!

一、Collectors

java.util.stream.Collectors,是從JDK1.8開始新引入的一個(gè)類。從源碼的類注釋上,我們可以知道:<u>Collectors實(shí)現(xiàn)了各種有用歸約的操作,例如類型歸類到新集合、根據(jù)不同標(biāo)準(zhǔn)匯總元素等。</u>透過示例,能讓我們眼前一亮,短短的一行代碼卻能處理如此強(qiáng)大、復(fù)雜的功能:匯總、拼接、累加計(jì)算、分組等。

<u>切記,不要用錯(cuò)哦,是java.util.stream.Collectors,不是java.util.Collections。</u>

/**
 * Implementations of {@link Collector} that implement various useful reduction
 * operations, such as accumulating elements into collections, summarizing
 * elements according to various criteria, etc.
 *
 * <p>The following are examples of using the predefined collectors to perform
 * common mutable reduction tasks:
 *
 * <pre>{@code
 *     // Accumulate names into a List
 *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
 *
 *     // Accumulate names into a TreeSet
 *     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
 *
 *     // Convert elements to strings and concatenate them, separated by commas
 *     String joined = things.stream()
 *                           .map(Object::toString)
 *                           .collect(Collectors.joining(", "));
 *
 *     // Compute sum of salaries of employee
 *     int total = employees.stream()
 *                          .collect(Collectors.summingInt(Employee::getSalary)));
 *
 *     // Group employees by department
 *     Map<Department, List<Employee>> byDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment));
 *
 *     // Compute sum of salaries by department
 *     Map<Department, Integer> totalByDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment,
 *                                                   Collectors.summingInt(Employee::getSalary)));
 *
 *     // Partition students into passing and failing
 *     Map<Boolean, List<Student>> passingFailing =
 *         students.stream()
 *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
 *
 * }</pre>
 *
 * @since 1.8
 */

換句話說,Collectors結(jié)合Stream將成為集合的終極操作,其中,包括:

  • 類型歸類:將集合中元素按照類型、條件過濾等歸類,存放到指定類型的新集合。

  • 分組:按照條件對(duì)元素進(jìn)行分組,和SQL中group by的用法有異曲同工之妙。

  • 分區(qū):分組的特殊情況,實(shí)質(zhì)是在做二分組,將符合條件、不符合條件的元素分組到兩個(gè)key分別為truefalseMap中,從而我們能夠得到符合和不符合的分組新集合。

  • 最值:按照某個(gè)屬性查找最大、最小元素。

  • 累加、匯總:用來完成累加計(jì)算、數(shù)據(jù)匯總(總數(shù)、總和、最小值、最大值、平均值)。

  • 連接:將元素以某種規(guī)則連接起來。

  • ……

二、實(shí)戰(zhàn)演練

1. 類型歸類

將集合中元素按照類型、條件過濾等歸類,存放到指定類型的新集合,List、Map、Set、Collection或者ConcurrentMap。涉及以下方法:

  • Collectors.toList()

  • Collectors.toMap()

  • Collectors.toSet()

  • Collectors.toCollection()

  • Collectors.toConcurrentMap()

一般都作為終止操作符cololect的參數(shù)來使用,并伴隨著流的結(jié)束。

常用于收集、篩選出集合(復(fù)雜集合)中的符合條件的數(shù)據(jù),并存放于對(duì)應(yīng)類型的新集合中,便于后續(xù)實(shí)際業(yè)務(wù)邏輯處理。

比如,將名字類型歸類存在到List<String>集合中:

List<String> list = allPeoples.stream().map(People::getName).collect(Collectors.toList());

2. 分組

按照條件對(duì)元素進(jìn)行分組,和 SQL 中的 group by 用法有異曲同工之妙,通常也建議使用Java代碼進(jìn)行分組處理以減輕數(shù)據(jù)庫(kù)SQL壓力。

分組涉及以下方法:

  • Collectors.groupingBy(…):普通分組。

  • Collectors.groupingByConcurrent(…):線程安全的分組。

分組后,返回的是一個(gè)Map集合,其中key作為分組對(duì)象,value作為對(duì)應(yīng)分組結(jié)果。

比如,考慮到People集合中可能會(huì)存在同齡人,將集合按照年齡進(jìn)行分組:

Map<Integer, List<People>> groupingByAge = allPeoples.stream().collect(Collectors.groupingBy(People::getAge));

如果我們不想返回MapvalueList怎么辦?實(shí)際上可以按照下面的方式分組:

Map<Integer, Set<People>> groupingByAge2 = allPeoples.stream().collect(Collectors.groupingBy(People::getAge, Collectors.toSet()));

考慮到同步安全問題時(shí),怎么辦?

采用線程安全的分組Collectors.groupingByConcurrent(…),于是:

Map<Integer, List<People>> groupingByAge3 = allPeoples.stream().collect(Collectors.groupingByConcurrent(People::getAge));

3. 分區(qū)

是分組的特殊情況,采用Collectors.partitioningBy(…)方法來完成。

該方法實(shí)質(zhì)是在做二分組,將符合條件、不符合條件的元素分組到兩個(gè)key分別為truefalseMap中,從而我們能夠得到符合和不符合的分組新集合。

比如,People集合中人名有中文名,也有英文名,將人名按照中、英文名進(jìn)行分區(qū):

Map<Boolean, List<People>> partitioningByName = allPeoples.stream().collect(Collectors.partitioningBy(people -> people.getName().matches("^[a-zA-Z]*")));
// 獲取英文名集合
List<People> englishNames = partitioningByName.get(true);
// 獲取中文名集合
List<People> chineseNames = partitioningByName.get(false);

4. 最值

按照某個(gè)屬性查找出最大或最小值元素,并且基于Comparator接口來對(duì)其進(jìn)行比較,返回一個(gè)Optional對(duì)象,并結(jié)合Optional.isPresent()判斷并取得最大或最小值。

涉及以下方法:

  • Collectors.maxBy(…):最大值。

  • Collectors.minBy(…):最小值。

比如,找到People集合中最大、最小年齡的人:

// 查找最大年齡的人
Optional<People> maxAgeOptional = allPeoples.stream().collect(Collectors.maxBy(Comparator.comparingInt(People::getAge)));
People maxAgePeople = null;
if (maxAgeOptional.isPresent()) {
	maxAgePeople = maxAgeOptional.get();
}
// 查找最小年齡的人
Optional<People> minAgeOptional = allPeoples.stream().collect(Collectors.minBy(Comparator.comparingInt(People::getAge)));
People minAgePeople = null;
if (minAgeOptional.isPresent()) {
	minAgePeople = minAgeOptional.get();
}

5. 累加、匯總

用來完成累加計(jì)算、數(shù)據(jù)匯總(總數(shù)、總和、最小值、最大值、平均值)操作。

計(jì)算集合某個(gè)屬性的總和,類似與SQL中的sum函數(shù)。

涉及以下方法:

  • Collectors.summingInt/Double/Long(…):按照某個(gè)屬性求和。

  • Collectors.summarizingInt/Double/Long(…):按照某個(gè)屬性的數(shù)據(jù)進(jìn)行匯總,得到其總數(shù)、總和、最小值、最大值、平均值。

比如,計(jì)算全體人員的薪資總和:

int salaryTotal = allPeoples.stream().collect(Collectors.summingInt(People::getSalary));

如果想要得到全體人員的薪資數(shù)據(jù)整體情況(包括總數(shù)、總和、最小值、最大值、平均值),怎么辦呢?

難道分別要搞多個(gè)Stream流嗎?

當(dāng)然,沒有這么麻煩,只需Collectors.summarizingInt方法就可輕松搞定。

// 輸出:IntSummaryStatistics{count=10, sum=45000, min=2000, average=4500.000000, max=7000}
IntSummaryStatistics intSummaryStatistics = allPeoples.stream().collect(Collectors.summarizingInt(People::getSalary));

6. 連接

將元素以某種規(guī)則連接起來,得到一個(gè)連接字符串。

涉及以下方法:

  • Collectors.joining():字符串直接連接。

  • Collectors.joining(CharSequence delimiter):按照字符delimiter進(jìn)行字符串連接。

  • Collectors.joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix):按照前綴prefix,后綴suffix,并以字符delimiter進(jìn)行字符串連接。

比如,將People集合中所有名字按照某種連接符進(jìn)行字符串連接:

// 輸出:xcbeyondNikiXiaoMing超哥小白小紅LucyLily超級(jí)飛俠樂迪
String namesStr1 = allPeoples.stream().map(People::getName).collect(Collectors.joining());
// 輸出:xcbeyond,Niki,XiaoMing,超哥,小白,小紅,Lucy,Lily,超級(jí)飛俠,樂迪
String namesStr2 = allPeoples.stream().map(People::getName).collect(Collectors.joining(","));
// 輸出:[xcbeyond,Niki,XiaoMing,超哥,小白,小紅,Lucy,Lily,超級(jí)飛俠,樂迪]
String namesStr3 = allPeoples.stream().map(People::getName).collect(Collectors.joining(",", "[", "]"));

三、總結(jié)

本文,只是針對(duì)JDK1.8java.util.stream.Collectors中最好用的操作進(jìn)行單獨(dú)舉例說明,不涉及嵌套、復(fù)合、疊加使用,實(shí)際業(yè)務(wù)場(chǎng)景下可能會(huì)涉及到多種操作的疊加、組合使用,需按需靈活使用即可。

如果你熟悉了上面這些操作,在面對(duì)復(fù)雜集合、處理復(fù)雜邏輯時(shí),就會(huì)更加得心應(yīng)手。尤其是分組、匯總,簡(jiǎn)直是太好用了。

感謝各位的閱讀,以上就是“JDK1.8新特性Stream的功能介紹”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)JDK1.8新特性Stream的功能介紹這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI