深入理解Java8新特性之Stream API的終止操作步驟
1.寫在前面
承接了上一篇文章(說(shuō)完了Stream API的創(chuàng)建方式及中間操作):深入理解Java8新特性之Stream API的創(chuàng)建方式和中間操作步驟。
我們都知道Stream API完成的操作是需要三步的:創(chuàng)建Stream → 中間操作 → 終止操作。那么這篇文章就來(lái)說(shuō)一下終止操作。
2.終止操作
終端操作會(huì)從流的流水線生成結(jié)果。其結(jié)果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
2.1 終止操作之查找與匹配

首先,我們?nèi)匀恍枰粋€(gè)自定義的Employee類,以及一個(gè)存儲(chǔ)它的List集合。
在Employee類定義了枚舉(BUSY:忙碌;FREE:空閑;VOCATION:休假)
package com.szh.java8;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee2 {
private Integer id;
private String name;
private Integer age;
private Double salary;
private Status status;
public Employee2(Integer id) {
this.id = id;
}
public Employee2(Integer id, String name) {
this.id = id;
this.name = name;
}
public enum Status {
FREE,
BUSY,
VOCATION
}
}
List<Employee2> employees = Arrays.asList(
new Employee2(1001,"張三",26,6666.66, Employee2.Status.BUSY),
new Employee2(1002,"李四",50,1111.11,Employee2.Status.FREE),
new Employee2(1003,"王五",18,9999.99,Employee2.Status.VOCATION),
new Employee2(1004,"趙六",35,8888.88,Employee2.Status.BUSY),
new Employee2(1005,"田七一",44,3333.33,Employee2.Status.FREE),
new Employee2(1005,"田七二",44,3333.33,Employee2.Status.VOCATION),
new Employee2(1005,"田七七",44,3333.33,Employee2.Status.BUSY)
);
查找所有的員工是否都處于BUSY狀態(tài)、至少有一個(gè)員工處于FREE狀態(tài)、沒(méi)有員工處于VOCATION狀態(tài)。
@Test
public void test1() {
boolean b1 = employees.stream()
.allMatch((e) -> e.getStatus().equals(Employee2.Status.BUSY));
System.out.println(b1);
boolean b2 = employees.stream()
.anyMatch((e) -> e.getStatus().equals(Employee2.Status.FREE));
System.out.println(b2);
boolean b3 = employees.stream()
.noneMatch((e) -> e.getStatus().equals(Employee2.Status.VOCATION));
System.out.println(b3);
}

對(duì)員工薪資進(jìn)行排序之后,返回第一個(gè)員工的信息; 篩選出BUSY狀態(tài)員工之后,返回任意一個(gè)處于BUSY狀態(tài)的員工信息。
@Test
public void test2() {
Optional<Employee2> op1 = employees.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op1.get());
System.out.println("----------------------------------");
Optional<Employee2> op2 = employees.stream()
.filter((e) -> e.getStatus().equals(Employee2.Status.BUSY))
.findAny();
System.out.println(op2.get());
}

下面,我們來(lái)看一下另外一組查找與匹配的方法。

計(jì)算處于VOCATION狀態(tài)的員工數(shù)量;對(duì)員工薪資字段進(jìn)行映射,同時(shí)獲取其中的最高薪資;獲取年齡最小的員工信息。
@Test
public void test3() {
long count = employees.stream()
.filter((e) -> e.getStatus().equals(Employee2.Status.VOCATION))
.count();
System.out.println(count);
Optional<Double> op1 = employees.stream()
.map(Employee2::getSalary)
.max(Double::compare);
System.out.println(op1.get());
Optional<Employee2> op2 = employees.stream()
.min((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge()));
System.out.println(op2.get());
}

在這里,大家需要注意的一點(diǎn)就是:當(dāng)前Stream流一旦進(jìn)行了終止操作,就不能再次使用了。
我們看下面的代碼案例。(異常信息說(shuō)的是:stream流已經(jīng)被關(guān)閉了)
@Test
public void test4() {
Stream<Employee2> stream = employees.stream()
.filter((e) -> e.getStatus().equals(Employee2.Status.BUSY));
long count = stream.count();
stream.map(Employee2::getName);
}

2.2 終止操作之歸約與收集


Collector 接口中方法的實(shí)現(xiàn)決定了如何對(duì)流執(zhí)行收集操作 (如收集到 List、Set、Map) 。但是 Collectors 實(shí)用類提供了很多靜態(tài)方法,可以方便地創(chuàng)建常見(jiàn)收集器實(shí)例,具體方法與實(shí)例如下表:


計(jì)算整數(shù)1~10的和;對(duì)員工薪資字段進(jìn)行映射,之后獲取所有員工的薪資總和。
@Test
public void test1() {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
System.out.println("-------------------------------");
Optional<Double> optional = employees.stream()
.map(Employee2::getSalary)
.reduce(Double::sum);
System.out.println(optional.get());
}

依次對(duì)我們先前定義好的存儲(chǔ)員工信息的List集合 做name字段的映射,然后 轉(zhuǎn)為 List、Set、HashSet(使用 Collectors 實(shí)用類中的靜態(tài)方法即可完成)。
在Set、HashSet集合中,由于元素是無(wú)序、不可重復(fù)的,所以只有一個(gè)田七二。
@Test
public void test2() {
List<String> list = employees.stream()
.map(Employee2::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("-------------------------------");
Set<String> set = employees.stream()
.map(Employee2::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("-------------------------------");
HashSet<String> hashSet = employees.stream()
.map(Employee2::getName)
.collect(Collectors.toCollection(HashSet::new));
hashSet.forEach(System.out::println);
}

對(duì)員工薪資字段做映射,之后通過(guò)比較器獲取最高薪資;
不做映射處理,直接通過(guò)比較器獲取薪資最低的員工信息;
計(jì)算所有員工的薪資總和;
計(jì)算所有員工的平均薪資;
計(jì)算員工總數(shù);
對(duì)員工薪資字段做映射,之后通過(guò)比較器獲取最高薪資;
@Test
public void test3() {
Optional<Double> max = employees.stream()
.map(Employee2::getSalary)
.collect(Collectors.maxBy(Double::compare));
System.out.println(max.get());
Optional<Employee2> min = employees.stream()
.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(min.get());
Double sum = employees.stream()
.collect(Collectors.summingDouble(Employee2::getSalary));
System.out.println(sum);
Double avg = employees.stream()
.collect(Collectors.averagingDouble(Employee2::getSalary));
System.out.println(avg);
Long count = employees.stream()
.collect(Collectors.counting());
System.out.println(count);
DoubleSummaryStatistics dss = employees.stream()
.collect(Collectors.summarizingDouble(Employee2::getSalary));
System.out.println(dss.getMax());
}

單個(gè)條件分組:根據(jù)員工狀態(tài)對(duì)Stream流進(jìn)行分組。 因?yàn)榉纸M之后得到的是一個(gè)Map集合,key就是員工狀態(tài),value則是一個(gè)List集合。
@Test
public void test4() {
Map<Employee2.Status, List<Employee2>> map = employees.stream()
.collect(Collectors.groupingBy(Employee2::getStatus));
Set<Map.Entry<Employee2.Status, List<Employee2>>> set = map.entrySet();
Iterator<Map.Entry<Employee2.Status, List<Employee2>>> iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry<Employee2.Status, List<Employee2>> entry = iterator.next();
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
}

多個(gè)條件分組:先按照員工狀態(tài)分組,如果狀態(tài)相同,再按照員工年齡分組。
@Test
public void test5() {
Map<Employee2.Status, Map<String, List<Employee2>>> map = employees.stream()
.collect(Collectors.groupingBy(Employee2::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() <= 35) {
return "成年";
} else if (e.getAge() <= 60) {
return "中年";
} else {
return "老年";
}
})));
Set<Employee2.Status> set = map.keySet();
Iterator<Employee2.Status> iterator = set.iterator();
while (iterator.hasNext()) {
Employee2.Status next = iterator.next();
Map<String, List<Employee2>> listMap = map.get(next);
System.out.println(next);
System.out.println(listMap);
}
}

根據(jù)特定的條件對(duì)員工進(jìn)行分區(qū)處理。(員工薪資大于等于5000為 true 分區(qū);否則都為 false 分區(qū))。
@Test
public void test6() {
Map<Boolean, List<Employee2>> map = employees.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));
map.forEach((key,value) -> System.out.println("鍵:" + key + ", 值:" + value));
}

以上就是深入理解Java8新特性之Stream API的終止操作步驟的詳細(xì)內(nèi)容,更多關(guān)于Java8 Stream API 終止操作的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
完美解決idea創(chuàng)建文件時(shí),文件不分級(jí)展示的情況
這篇文章主要介紹了完美解決idea創(chuàng)建文件時(shí),文件不分級(jí)展示的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
關(guān)于Filter中獲取請(qǐng)求體body后再次讀取的問(wèn)題
這篇文章主要介紹了關(guān)于Filter中獲取請(qǐng)求體body后再次讀取的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Java 并發(fā)編程學(xué)習(xí)筆記之核心理論基礎(chǔ)
編寫優(yōu)質(zhì)的并發(fā)代碼是一件難度極高的事情。Java語(yǔ)言從第一版本開(kāi)始內(nèi)置了對(duì)多線程的支持,這一點(diǎn)在當(dāng)年是非常了不起的,但是當(dāng)我們對(duì)并發(fā)編程有了更深刻的認(rèn)識(shí)和更多的實(shí)踐后,實(shí)現(xiàn)并發(fā)編程就有了更多的方案和更好的選擇。本文是對(duì)并發(fā)編程的核心理論做了下小結(jié)2016-05-05
Java 并發(fā)編程之ThreadLocal詳解及實(shí)例
這篇文章主要介紹了Java 并發(fā)編程之ThreadLocal詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02
Spring Cloud 配置中心內(nèi)容加密的配置方法
這篇文章主要介紹了Spring Cloud 配置中心內(nèi)容加密的配置方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06
Maven設(shè)置使用自定義的jar包到自己本地倉(cāng)庫(kù)
今天小編就為大家分享一篇關(guān)于Maven設(shè)置使用自定義的jar包到自己本地倉(cāng)庫(kù)的文章,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10
JAVA使用JDBC連接oracle數(shù)據(jù)庫(kù)的詳細(xì)過(guò)程
JDBC是一種用于執(zhí)行SQL語(yǔ)句的Java API,可以為多種關(guān)系數(shù)據(jù)庫(kù)提供統(tǒng)一訪問(wèn),它由一組用Java語(yǔ)言編寫的類和接口組成,下面這篇文章主要給大家介紹了關(guān)于JAVA使用JDBC連接oracle數(shù)據(jù)庫(kù)的詳細(xì)過(guò)程,需要的朋友可以參考下2023-05-05
SpringBoot使用AOP實(shí)現(xiàn)統(tǒng)一角色權(quán)限校驗(yàn)
這篇文章主要介紹了SpringBoot如何使用AOP實(shí)現(xiàn) 統(tǒng)一角色權(quán)限校驗(yàn),文中有詳細(xì)的代碼示例講解和操作流程,具有一定的參考價(jià)值,需要的朋友可以參考下2023-07-07

