Java8-新特性-Stream
Java 8 两个最重要的变化是 Lambda 和 Stream API。Stream 用来操作数据源生成的元素序列,Collection 上的 stream() 返回顺序流,parallelStream() 返回并发流。
Stream 自己不存元素、不改源对象,操作延迟执行。多个中间操作连成流水线,直到终止操作才一次性处理(惰性求值)。下面用 Employee 列表把 filter、map、collect 等跑一遍。
| 阶段 | 典型方法 | 结果 |
|---|---|---|
| 创建 | stream() / parallelStream() / of / iterate | 得到 Stream |
| 中间操作 | filter / map / distinct / sorted / limit | 仍是 Stream,可继续接 |
| 终止操作 | collect / forEach / reduce / count / max | 变成集合、值或 void |
| 收集 | Collectors.toList/toSet/groupingBy | 由 Collector 决定容器 |
了解Stream
Java8中有两个最为重要的改变,一个是Lambda表达式,另一个就是Stream API,针对常见的集合数据处理,Stream API 提供了一种高效且易于使用的数据处理方式。
什么是Stream
基本概念
流(Stream)用于操作数据源所生成的元素序列。Java 8给Collection接口增加了两个默认方法,它们可以返回一个Stream
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}//stream()返回的是一个顺序流default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}//parallelStream()返回的是一个并发流
-
Stream 自己不会存储元素。 -
Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。 -
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
基本示例
首先这里有一个Employee类
返回薪资大于5000的员工列表,java8以前是这样做的
使用Stream API ,代码可以这样
先通过stream()得到一个Stream对象,然后调用Stream上的方法,filter()过滤得到薪资大于5000的,它的返回值依然是一个Stream,然后通过调用collect()方法并传递一个Collectors.toList()将结果集存放到一个List中.
使用Stream API处理集合类代码更加简洁易读.
下面介绍一下Stream中的两种操作
Stream的中间操作和终止操作
中间操作:
多个 中间操作可以连接起来形成一个 流水线,除非流水线上触发终止操作,否则 中间操作不会执行任何的 处理!而在 终止操作时一次性全部 处理,称为“惰性求值”
终止操作:
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
收集 : collect(Collector c)方法需要一个Collector 作为参数,Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。Java8中提供了一个Collectors工具类, 工具中提供了很多静态方法,可以方便地创建常见收集器例
具体方法与实例如下表
这里只列出了一些常用的方法.具体参考Java8 Stream API
Stream API 使用
中间操作
-
映射(map/flatMap) map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);map操作会将流里的每个元素按mapper转换后的结果添加到一个新流中.
flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)它接受一个函数mapper,对流中的每一个元素,mapper会将该元素转换为一个流Stream,然后把新生成流的每一个元素传递给下一个操作.
flatMap 把 Stream 中的层级结构扁平化,就是将最底层元素抽出来放到一起,最终生成的新 Stream 里面都是直接的字符串。
-
排序(sort) sorted() ——自然排序(根据流中元素实现的Comparable接口的compareTo()方法来排序的)
sorted(Comparator com) ——定制排序(根据特定的比较器来排序)
-
筛选与切片 filter : 接受Lambda,从流中排除某些元素
limit(n) : 返回流中前n个元素
skip(n) : 跳过流中前n个元素
distinct : 去掉流中重复元素(通过hashCode和equles方法判断是否为相同对象)
filter
limit
skin
distinct
终止操作
-
查找与匹配
allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配的元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值
allMatch
anyMatch
noneMatch
findFirst
Optional<T>类是一个是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在Optional<T>可以更好的表达这个概念,并且可以避免空指针异常这里findFirst()查找第一个元素有可能为空,就把结果封装成一个Optional类.
-
规约(reduce) `reduce(T identity, BinaryOperator bo) / reduce(BinaryOperator) ——可以将流中元素按照指定的二院运算反复结合起来,得到一个值
identity : 起始值
BinaryOperator : 二元运算
这里reduce操作中,起始值为0,第一次x为0,list中第一个元素1为y 经行(x+y)操作,然后又把(x+y)的值作为x, list中第二个元素2作为y,依次累加.最终得到一个sum值
这个地方由于没有初始值,计算结果可能为空(列表为空的情况),所以就把计算结果封装到Optional中避免空指针异常
-
收集(collect)
collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
<R, A> R collect(Collector<? super T, A, R> collector);
-
分组
groupingBy : 根据指定的元素对流中数据进行分组
输出结果为:
田:[Employee [id=105, name=田七, age=38, salary=5555.55]
张:[Employee [id=101, name=张三, age=18, salary=9999.99]
赵:[Employee [id=104, name=赵六, age=20, salary=7777.77],
Employee [id=104, name=赵六, age=19, salary=7777.77],
Employee [id=104, name=赵四, age=40, salary=7777.77]]
王:[Employee [id=103, name=王五, age=28, salary=3333.33]
李:[Employee [id=102, name=李四, age=59, salary=6666.66]
-
分区
partitioningBy : 按照给定条件对流中元素进行分区
输出结果为:
false:[Employee [id=103, name=王五, age=28, salary=3333.33],
Employee [id=105, name=田七, age=38, salary=5555.55]]
true:[Employee [id=102, name=李四, age=59, salary=6666.66],
Employee [id=101, name=张三, age=18, salary=9999.99],
Employee [id=104, name=赵六, age=20, salary=7777.77],
Employee [id=104, name=赵六, age=19, salary=7777.77],
Employee [id=104, name=赵四, age=40, salary=7777.77]]
Optional 类
介绍
Optional 容器类:用于尽量避免空指针异常
方法
Optional 容器类:用于尽量避免空指针异常
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
小结
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。
简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式
原文链接 : Java8-新特性-Stream | 火尧
一句话总结:Stream 是惰性流水线:中间操作只描述怎么变,终止操作才真正算出 List/Optional/数值;不会改原集合。
转载请注明来源:Java8-新特性-Stream










