写在前面

如果你出去面试,面试官问了你关于Java8 Stream API的一些问题,比如:Java8中创建Stream流有哪几种方式?(可以参见:《【Java8新特性】面试官问我:Java8中创建Stream流有哪几种方式?》)Java8中的Stream API有哪些中间操作?(可以参见:《【Java8新特性】Stream API有哪些中间操作?看完你也可以吊打面试官!!》)如果你都很好的回答了这些问题,那么,面试官可能又会问你:Java8中的Stream API有哪些终止操作呢?没错,这就是Java8中有关Stream API的灵魂三问!不要觉得是面试官在为难你,只有你掌握了这些细节,你就可以反过来吊打面试官了!

Stream的终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer、Double、String等等,甚至是 void 。

在Java8中,Stream的终止操作可以分为:查找与匹配、规约和收集。接下来,我们就分别简单说明下这些终止操作。

查找与匹配

Stream API中有关查找与匹配的方法如下表所示。

方法 描述
allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值
forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代)

同样的,我们对每个重要的方法进行简单的示例说明,这里,我们首先建立一个Employee类,Employee类的定义如下所示。

@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Employee implements Serializable {
private static final long serialVersionUID = -9079722457749166858L;
private String name;
private Integer age;
private Double salary;
private Stauts stauts;
public enum Stauts{
WORKING,
SLEEPING,
VOCATION
}
}

接下来,我们在测试类中定义一个用于测试的集合employees,如下所示。

protected List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99, Employee.Stauts.SLEEPING),
new Employee("李四", 38, 5555.55, Employee.Stauts.WORKING),
new Employee("王五", 60, 6666.66, Employee.Stauts.WORKING),
new Employee("赵六", 8, 7777.77, Employee.Stauts.SLEEPING),
new Employee("田七", 58, 3333.33, Employee.Stauts.VOCATION)
);

好了,准备工作就绪了。接下来,我们就开始测试Stream的每个终止方法。

1.allMatch()

allMatch()方法表示检查是否匹配所有元素。其在Stream接口中的定义如下所示。

boolean allMatch(Predicate<? super T> predicate);

我们可以通过类似如下示例来使用allMatch()方法。

boolean match = employees.stream().allMatch((e) -> Employee.Stauts.SLEEPING.equals(e.getStauts()));
System.out.println(match);

注意:使用allMatch()方法时,只有所有的元素都匹配条件时,allMatch()方法才会返回true。

2.anyMatch()方法

anyMatch方法表示检查是否至少匹配一个元素。其在Stream接口中的定义如下所示。

boolean anyMatch(Predicate<? super T> predicate);

我们可以通过类似如下示例来使用anyMatch()方法。

boolean match = employees.stream().anyMatch((e) -> Employee.Stauts.SLEEPING.equals(e.getStauts()));
System.out.println(match);

注意:使用anyMatch()方法时,只要有任意一个元素符合条件,anyMatch()方法就会返回true。

3.noneMatch()方法

noneMatch()方法表示检查是否没有匹配所有元素。其在Stream接口中的定义如下所示。

boolean noneMatch(Predicate<? super T> predicate);

我们可以通过类似如下示例来使用noneMatch()方法。

boolean match = employees.stream().noneMatch((e) -> Employee.Stauts.SLEEPING.equals(e.getStauts()));
System.out.println(match);

注意:使用noneMatch()方法时,只有所有的元素都不符合条件时,noneMatch()方法才会返回true。

4.findFirst()方法

findFirst()方法表示返回第一个元素。其在Stream接口中的定义如下所示。

Optional<T> findFirst();

我们可以通过类似如下示例来使用findFirst()方法。

Optional<Employee> op = employees.stream().sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).findFirst();
System.out.println(op.get());

5.findAny()方法

findAny()方法表示返回当前流中的任意元素。其在Stream接口中的定义如下所示。

Optional<T> findAny();

我们可以通过类似如下示例来使用findAny()方法。

Optional<Employee> op = employees.stream().filter((e) -> Employee.Stauts.WORKING.equals(e.getStauts())).findFirst();
System.out.println(op.get());

6.count()方法

count()方法表示返回流中元素总数。其在Stream接口中的定义如下所示。

long count();

我们可以通过类似如下示例来使用count()方法。

long count = employees.stream().count();
System.out.println(count);

7.max()方法

max()方法表示返回流中最大值。其在Stream接口中的定义如下所示。

Optional<T> max(Comparator<? super T> comparator);

我们可以通过类似如下示例来使用max()方法。

Optional<Employee> op = employees.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op.get());

8.min()方法

min()方法表示返回流中最小值。其在Stream接口中的定义如下所示。

Optional<T> min(Comparator<? super T> comparator);

我们可以通过类似如下示例来使用min()方法。

Optional<Double> op = employees.stream().map(Employee::getSalary).min(Double::compare);
System.out.println(op.get());

9.forEach()方法

forEach()方法表示内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代)。其在Stream接口内部的定义如下所示。

void forEach(Consumer<? super T> action);

我们可以通过类似如下示例来使用forEach()方法。

employees.stream().forEach(System.out::println);

规约

Stream API中有关规约的方法如下表所示。

方法 描述
reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。 返回 T
reduce(BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。 返回 Optional

reduce()方法在Stream接口中的定义如下所示。

T reduce(T identity, BinaryOperator<T> accumulator);
Optional<T> reduce(BinaryOperator<T> accumulator);
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);

我们可以通过类似如下示例来使用reduce方法。

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> op = employees.stream().map(Employee::getSalary).reduce(Double::sum);
System.out.println(op.get());

我们也可以搜索employees列表中“张”出现的次数。

 Optional<Integer> sum = employees.stream()
.map(Employee::getName)
.flatMap(TestStreamAPI1::filterCharacter)
.map((ch) -> {
if(ch.equals('六'))
return 1;
else
return 0;
}).reduce(Integer::sum);
System.out.println(sum.get());

注意:上述例子使用了硬编码的方式来累加某个具体值,大家在实际工作中再优化代码。

收集

方法 描述
collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法

collect()方法在Stream接口中的定义如下所示。

<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner); <R, A> R collect(Collector<? super T, A, R> collector);

我们可以通过类似如下示例来使用collect方法。

Optional<Double> max = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.maxBy(Double::compare));
System.out.println(max.get());
Optional<Employee> op = employees.stream()
.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(op.get());
Double sum = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
Double avg = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
Long count = employees.stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("--------------------------------------------");
DoubleSummaryStatistics dss = employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getMax());

如何收集Stream流?

Collector接口中方法的实现决定了如何对流执行收集操作(如收集到 List、 Set、 Map)。 Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:

方法 返回类型 作用
toList List 把流中元素收集到List
toSet Set 把流中元素收集到Set
toCollection Collection 把流中元素收集到创建的集合
counting Long 计算流中元素的个数
summingInt Integer 对流中元素的整数属性求和
averagingInt Double 计算流中元素Integer属性的平均 值
summarizingInt IntSummaryStatistics 收集流中Integer属性的统计值。 如:平均值
joining String 连接流中每个字符串
maxBy Optional 根据比较器选择最大值
minBy Optional 根据比较器选择最小值
reducing 归约产生的类型 从一个作为累加器的初始值 开始,利用BinaryOperator与 流中元素逐个结合,从而归 约成单个值
collectingAndThen 转换函数返回的类型 包裹另一个收集器,对其结 果转换函数
groupingBy Map<K, List> 根据某属性值对流分组,属 性为K,结果为V
partitioningBy Map<Boolean, List> 根据true或false进行分区

每个方法对应的使用示例如下表所示。

方法 使用示例
toList List employees= list.stream().collect(Collectors.toList());
toSet Set employees= list.stream().collect(Collectors.toSet());
toCollection Collection employees=list.stream().collect(Collectors.toCollection(ArrayList::new));
counting long count = list.stream().collect(Collectors.counting());
summingInt int total=list.stream().collect(Collectors.summingInt(Employee::getSalary));
averagingInt double avg= list.stream().collect(Collectors.averagingInt(Employee::getSalary))
summarizingInt IntSummaryStatistics iss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary));
Collectors String str= list.stream().map(Employee::getName).collect(Collectors.joining());
maxBy Optionalmax= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)));
minBy Optional min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)));
reducing int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum));
collectingAndThen int how= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
groupingBy Map<Emp.Status, List> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus));
partitioningBy Map<Boolean,List>vd= list.stream().collect(Collectors.partitioningBy(Employee::getManage));
public void test4(){
Optional<Double> max = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.maxBy(Double::compare));
System.out.println(max.get()); Optional<Employee> op = emps.stream()
.collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))); System.out.println(op.get()); Double sum = emps.stream()
.collect(Collectors.summingDouble(Employee::getSalary)); System.out.println(sum); Double avg = emps.stream()
.collect(Collecors.averagingDouble(Employee::getSalary));
System.out.println(avg);
Long count = emps.stream()
.collect(Collectors.counting()); DoubleSummaryStatistics dss = emps.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getMax());

写在最后

如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习Java8新特性。

最后,附上Java8新特性核心知识图,祝大家在学习Java8新特性时少走弯路。

【Java8新特性】面试官:谈谈Java8中的Stream API有哪些终止操作?的更多相关文章

  1. 【Java8新特性】你知道Java8为什么要引入Lambda表达式吗?

    写在前面 这是一道真实的面试题,一个读者朋友出去面试,面试官竟然问他这样一个问题:你说说Java8中为什么引入Lambda表达式?引入Lambda表达式后有哪些好处呢?还好这个朋友对Java8早有准备 ...

  2. 2020你还不会Java8新特性?方法引用详解及Stream 流介绍和操作方式详解(三)

    方法引用详解 方法引用: method reference 方法引用实际上是Lambda表达式的一种语法糖 我们可以将方法引用看作是一个「函数指针」,function pointer 方法引用共分为4 ...

  3. java8新特性lamda表达式在集合中的使用

    1.利用stream().forEach()循环处理List; List<String> list = Lists.newArrayList();//新建一个List 用的google提供 ...

  4. Java8 新特性之Stream----java.util.stream

    这个包主要提供元素的streams函数操作,比如对collections的map,reduce. 例如: int sum = widgets.stream() .filter(b -> b.ge ...

  5. 2020你还不会Java8新特性?

    Java8(1)新特性介绍及Lambda表达式 前言: 跟大娃一块看,把原来的电脑拿出来放中间看视频用 --- 以后会有的课程 难度 深入Java 8 难度1 并发与netty 难度3 JVM 难度4 ...

  6. Java8新特性(一)之Lambda表达式

    .personSunflowerP { background: rgba(51, 153, 0, 0.66); border-bottom: 1px solid rgba(0, 102, 0, 1); ...

  7. 【Java8新特性】面试官问我:Java8中创建Stream流有哪几种方式?

    写在前面 先说点题外话:不少读者工作几年后,仍然在使用Java7之前版本的方法,对于Java8版本的新特性,甚至是Java7的新特性几乎没有接触过.真心想对这些读者说:你真的需要了解下Java8甚至以 ...

  8. 【Java8新特性】Stream API有哪些中间操作?看完你也可以吊打面试官!!

    写在前面 在上一篇<[Java8新特性]面试官问我:Java8中创建Stream流有哪几种方式?>中,一名读者去面试被面试官暴虐!归根结底,那哥儿们还是对Java8的新特性不是很了解呀!那 ...

  9. Java8新特性(一)_interface中的static方法和default方法

    什么要单独写个Java8新特性,一个原因是我目前所在的公司用的是jdk8,并且框架中用了大量的Java8的新特性,如上篇文章写到的stream方法进行过滤map集合.stream方法就是接口Colle ...

随机推荐

  1. 数学--数论--HDU 4675 GCD of Sequence(莫比乌斯反演+卢卡斯定理求组合数+乘法逆元+快速幂取模)

    先放知识点: 莫比乌斯反演 卢卡斯定理求组合数 乘法逆元 快速幂取模 GCD of Sequence Alice is playing a game with Bob. Alice shows N i ...

  2. c/c++获取文件夹下所有文件名

    如何获取某一文件夹下所有文件名,是一个很有意思的问题.网上代码很多,找了个简单的,特此收录. #include <iostream> #include <io.h> #incl ...

  3. MODIS系列之NDVI(MOD13Q1)七:时间序列S-G滤波之Python

    时间序列S-G滤波之Python 根据上上篇博文(MODIS系列之NDVI(MOD13Q1)五:NDVI处理流程)做出的NDVI.我们求NDVI时间序列图,但该NDVI时序图为地表各土地类型综合的ND ...

  4. Hadoop-wordCount实例代码编写(Hadoop学习第四天)

    1.新建一个maven项目2.pom文件中引入以下jar包<dependency> <groupId>org.apache.hadoop</groupId> < ...

  5. Day_09【常用API】扩展案例3_删除源字符串中的指定字符,并计算指定字符出现的次数

    分析以下需求,并用代码实现 1.键盘录入一个源字符串由字符串变量scrStr接收 2.键盘录入一个要删除的字符串由字符串变量delStr接收 3.要求 删除该字scrStr符串中的所有delStr字符 ...

  6. ubuntu文件系统修改( for arm)

    系统:ubuntu14.04 镜像:ubuntu-rootfs.img for aarch64 创建一个文件夹 ubuntu-mount mkdir ubuntu-mount 将ubuntu-root ...

  7. search(12)- elastic4s-聚合=桶+度量

    这篇我们介绍一下ES的聚合功能(aggregation).聚合是把索引数据可视化处理成可读有用数据的主要工具.聚合由bucket桶和metrics度量两部分组成. 所谓bucket就是SQL的GROU ...

  8. Istio的流量管理(实操一)(istio 系列三)

    Istio的流量管理(实操一)(istio 系列三) 使用官方的Bookinfo应用进行测试.涵盖官方文档Traffic Management章节中的请求路由,故障注入,流量迁移,TCP流量迁移,请求 ...

  9. JAVA实现拼手气红包算法

    实现拼手气红包算法,有以下几个需要注意的地方: 抢红包的期望收益应与先后顺序无关 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如 ...

  10. sqli-labs之Page-4

    第五十四关 题目给出了数据库名为challenges. 这一关是依旧字符型注入,但是尝试10次后,会强制更换表名等信息.所以尽量在认真思考后进行尝试 爆表名 ?id=-1' union select ...