8.2.6 使用Java8新增的Stream操作集合
8.2.6 使用Java 8新增的Stream操作集合
Java 8
还新增了Stream
、 IntStream
、 LongStream
、 DoubleStream
等流式API
,这些API
代表多个支持串行
和并行
聚集操作的元素。上面4个接口中, Stream
是一个通用的流接口,而IntStream
、 LongStream
、DoubleStream
则代表元素类型为int
、long
、 double
的流。
如何创建类型为int long double的Stream
Java 8
为上面每个流式API
提供了对应的Builder
,例如Stream.Builder
、 IntStream.Builder
、LongStream.Builder
、 DoubleStream.Builder
,开发者可以通过这些Builder
来创建对应的流。
独立使用Stream的步骤
独立使用Stream
的步骤如下:
- 使用
Stream
或XxxStream
的builder()
类方法创建该Stream
对应的Builder
。 - 重复调用
Builder
的add()
方法向该流中添加多个元素。 - 调用
Builder
的build()
方法获取对应的Stream
- 调用
Stream
的聚集方法。
在上面4个步骤中,第4步可以根据具体需求来调用不同的方法, Stream
提供了大量的聚集方法供用户调用,具体可参考Stream
或XxxStream
的API
文档。
每个Stream只能执行一次
对于大部分聚集方法而言,每个Stream
只能执行一次。
程序 IntStream使用示例
1 |
|
上面程序先创建了一个IntStream
,接下来分别多次调用IntStream
的聚集方法执行操作,这样即可获取该流的相关信息。注意:IntStream
的方法每次只能执行一个,因此需要把其他代码注释掉。
中间方法和末端方法
Stream
提供了大量的方法进行聚集操作,这些方法既可以是”中间的”(intermediate
),也可以是”末端的”(terminal
)。
中间方法
:中间操作允许流保持打开状态,并允许直接调用后续方法。上面程序中的map()
方法就是中间方法。中间方法的返回值是另外一个流。末端方法
:末端方法是对流的最终操作。当对某个Stream
执行末端方法后,该流将会被”消耗”且不再可用。上面程序中的sum()
、count()
、average()
等方法都是末端方法。
流的方法有什么特征
除此之外,关于流的方法还有如下两个特征。
有状态的方法
:这种方法会给流增加一些新的属性,比如元素的唯一性、元素的最大数量,保证元素以排序的方式被处理等。有状态的方法往往需要更大的性能开销。短路方法
:短路方法可以尽早结束对流的操作,不必检査所有的元素。
Stream常用的中间方法
下面简单介绍一下Stream
常用的中间方法。
Stream 中间方法 |
描述 |
---|---|
Stream<T> filter(Predicate<? super T> predicate) |
过滤Stream 中所有不符合predicate 的元素。 |
IntStream mapToInt(ToIntFunction<? super T> mapper) |
使用ToIntFunction 对流中的元素执行一对一的转换,该法返回的新流中包含了ToIntFunction 转换生成的所有元素。 |
LongStream mapToLong(ToLongFunction<? super T> mapper) |
Returns a LongStream consisting of the results of applying the given function to the elements of this stream. |
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) |
Returns a DoubleStream consisting of the results of applying the given function to the elements of this stream. |
Stream<T> peek(Consumer<? super T> action) |
依次对每个元素执行一些操作,该方法返回的流与原有流包含相同的素。该方法主要用于调试. |
Stream<T> distinct() |
该方法用于排序流中所有重复的元素(判断元素重复的标准是使 equals() 比较返回true )这是一个有状态的方法 |
Stream<T> sorted() |
该方法用于保证流中的元素在后续的访问中处于有序状态。这是一个有状态的方法。 |
Stream<T> sorted(Comparator<? super T> comparator) |
Returns a stream consisting of the elements of this stream, sorted according to the provided |
Stream<T> limit(long maxSize) |
该方法用于保证对该流的后续访问中最大允许访问的元素个数。这是一个有状态的、短路方法。 |
Stream常用的末端方法
下面简单介绍一下Stream
常用的末端方法。
方法 | 描述 |
---|---|
void forEach(Consumer<? super T> action) |
遍历流中所有元素,对每个元素执行action |
将流转成数组
方法 | 描述 |
---|---|
Object[] toArray() |
将流中所有元素转换为一个数组。 |
<A> A[] toArray(IntFunction<A[]> generator) |
Returns an array containing the elements of this stream, using the provided generator function to allocate the returned array, as well as any additional arrays that might be required for a partitioned execution or for resizing. |
合并流中的元素:reduce方法
该方法有三个重载的版本,都用于通过某种操作来合并流中的元素。
方法 | 描述 |
---|---|
Optional<T> reduce(BinaryOperator<T> accumulator) |
Performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any. |
T reduce(T identity, BinaryOperator<T> accumulator) |
Performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value. |
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner) |
Performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions. |
求最大值 最小值 统计流中元素数量
方法 | 描述 |
---|---|
Optional<T> max(Comparator<? super T> comparator) |
返回流中所有元素的最大值 |
Optional<T> min(Comparator<? super T> comparator) |
返回流中所有元素的最小值 |
long count() |
返回流中所有元素的数量。 |
判断流中的元素是否符合Predicate
条件
方法 | 描述 |
---|---|
boolean allMatch(Predicate<? super T> predicate) |
判断流中是否每个元素都符合Predicate 条件。 |
boolean anyMatch(Predicate<? super T> predicate) |
判断流中是否至少包含一个元素符合Predicate 条件。 |
boolean noneMatch(Predicate<? super T> predicate) |
判断流中是否所有元素都不符合Predicate 条件 |
返回流中的元素
方法 | 描述 |
---|---|
Optional<T> findFirst() |
返回流中的第一个元素。 |
Optional<T> findAny() |
返回流中的任意一个元素。 |
获取集合对应的流
Java 8
允许使用流式API
来操作集合, Collection
接口提供了一个stream()
默认方法,该方法可返回该集合对应的流,接下来即可通过流式API
来操作集合元素。由于Stream
可以对集合元素进行整体的聚集操作,因此Stream
极大地丰富了集合的功能。
Collection 接口的stream 方法 |
描述 |
---|---|
default Stream<E> stream() |
Returns a sequential Stream with this collection as its source. |
程序 使用流操作集合
例如,对于8.2.5节介绍的示例程序,该程序需要额外定义一个calAll()
方法来遍历集合元素,然后依次对每个集合元素进行判断——这太麻烦了。如果使用Stream
,那么就直接对集合中所有元素进行批量操作。
下面使用Stream
来改写这个程序。
1 | import java.util.Collection; |
运行效果:
1 | 包含字符C的元素个数:2 |
从上面程序中的代码可以看出,
程序只要调用Collection
的stream()
方法即可返回该集合对应的Stream
,接下来就可通过Stream
提供的方法对所有集合元素进行处理,这样大大地简化了集合编程的代码。
上面程序中最后一段代码:
1 | IntStream intStream = collection.stream().mapToInt(str -> str.length()); |
先调用Collection
对象的stream()
方法将集合转换为Stream
对象,然后调用Stream
对象的mapToInt()
方法将其转换为IntStream
——这个mapToInt()
方法就是一个中间方法,因此程序可继续调用IntStream
的forEach()
方法来遍历流中的元素。