Java SE 9:Stream API的改进

时间:2020-02-23 14:37:02  来源:igfitidea点击:

在本文中,我们将首先讨论Java SE 8 Stream API的基础知识,然后介绍Java SE 9 Stream API的改进。
在下一部分中,让我们从Stream API基础开始。

Java SE 8:Stream API基础

众所周知,Stream API是Oracle Corp在Java SE 8版本中引入的重大变化之一。
另一个重大变化是Lambda Expressions。

什么是流?流是一系列元素,并轻松支持一组聚合操作。
它根据我们的要求以顺序或者并行方式支持这些操作。
Oracle Corp已在java.util.stream包下定义了此New Stream API。

此API中重要的是Stream接口。
此Stream API的主要优点是它支持内部迭代。
由于Stream API中的这一新功能,我们可以以惰性和并行方式执行操作。

现在让我们执行一些Stream操作。

例:

jshell> import java.util.stream.*

jshell> Stream stream = Stream.of(1,2,3,4,5,6,7,8,9,10)
stream ==> java.util.stream.ReferencePipeline$Head@64bfbc86

jshell> stream.forEach(x -> System.out.println(x));
1
2
3
4
5
6
7
8
9
10

要阅读有关Java SE 8 Stream API基础的更多信息,请通读本教程:Java 8 Stream。

Java SE 9:Stream API的改进

在Java SE 9中,Oracle Corp向java.util.Stream接口添加了以下四个有用的新方法。

  • dropWhile
  • takeWhile
  • iterate
  • ofNullable

由于Stream是接口,因此前两个新方法是默认方法,后两个是静态方法。
其中两个非常重要:dropWhile和takeWhile方法。

如果您熟悉Scala语言或者任何函数编程语言,则一定会知道这些方法。
这些是编写某些功能样式代码的非常有用的方法。
让我们在接下来的部分中逐一讨论它们,并提供描述和有用的示例。

Java SE 9:流API takeWhile()方法

在Stream API中,takeWhile()方法返回与Predicate条件匹配的最长前缀元素。

它以谓词作为参数。
谓词是布尔表达式,它返回true或者false。
对于有序和无序流,其行为有所不同。
让我们通过下面的一些简单示例对其进行探讨。

流API:

default Stream<T> takeWhile(Predicate<? super T> predicate)

如果Stream是有序的,则takeWhile方法将返回与该谓词匹配的最长前缀。
结果流仅包含与该谓词条件匹配的那个前缀元素。

有序流示例:

jshell> Stream<Integer> stream = Stream.of(1,2,3,4,5,6,7,8,9,10)
stream ==> java.util.stream.ReferencePipeline$Head@55d56113

jshell> stream.takeWhile(x -> x < 4).forEach(a -> System.out.println(a))
1
2
3

由于此Stream是有序的,因此takeWhile()方法将返回与谓词匹配的前三个元素。
这里的谓词是"元素必须小于4"。

无序流示例:

jshell> Stream<Integer> stream = Stream.of(1,2,4,5,3,6,7,8,9,10)
stream ==> java.util.stream.ReferencePipeline$Head@55d56113

jshell> stream.takeWhile(x -> x < 4).forEach(a -> System.out.println(a))
1
2

由于此Stream是无序的,因此takeWhile()方法将返回与谓词匹配的前两个元素。

这意味着takeWhile()返回所有带前缀的元素,直到它们匹配谓词条件为止。
当该谓词为第一个元素返回false时,它将停止求值并返回该子集元素。
对该谓词进行评估,直到第一次返回false为止。

Java SE 9:Stream API dropWhile方法

在Stream API中,dropWhile()方法删除与谓词匹配的最长前缀元素,并返回其余元素。

它以谓词作为参数。
谓词是布尔表达式,它返回true或者false。
对于有序和无序流,其行为有所不同。
让我们通过下面的一些简单示例对其进行探讨。

流API:

default Stream<T> dropWhile(Predicate<? super T> predicate)

如果Stream是有序的,则dropWhile方法将删除与该谓词匹配的最长前缀元素,并返回其余元素。
结果流包含除与谓词条件匹配的那些前缀元素之外的所有元素。

有序流示例:

jshell> Stream<Integer> stream = Stream.of(1,2,3,4,5,6,7,8,9,10)
stream ==> java.util.stream.ReferencePipeline$Head@55d56113

jshell> stream.dropWhile(x -> x < 4).forEach(a -> System.out.println(a))
4
5
6
7
8
9
10

由于此Stream是有序的,因此dropWhile()方法将删除与谓词匹配的前三个元素,并将其余元素返回到结果Stream中。
这里的谓词是"元素必须小于4"。

无序流示例:

jshell> Stream<Integer> stream = Stream.of(1,2,4,5,3,6,7,8,9,10)
stream ==> java.util.stream.ReferencePipeline$Head@55d56113

jshell> stream.dropWhile(x -> x < 4).forEach(a -> System.out.println(a))
4
5
3
6
7
8
9
10

由于此Stream是无序的,因此dropWhile()方法仅删除与我们的谓词匹配的前两个元素,并将其余元素返回到生成的Stream中。

这意味着dropWhile()首先删除所有带前缀的元素,直到它们匹配谓词条件为止。
当该谓词对第一个元素返回false时,它将停止求值,并将其余子集元素返回到结果Stream中。

Java SE 9:Stream API迭代方法

在Stream API中,iterate()返回以InitialValue(第一个参数)开头,匹配Predicate(第二个参数)并使用第三个参数生成下一个元素的元素流。

流API:

static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)

它类似于for循环:第一个参数是初始值,下一个参数是条件,最后一个参数是生成下一个元素(例如,递增或者递减运算)。

Java SE 9 IntStream迭代示例:

jshell> IntStream.iterate(2, x -> x < 20, x -> x * x).forEach(System.out::println)
2
4
16

其中Stream以元素" 2"开始,然后执行条件" 2 <20"为真,则打印值;在下一次迭代中,递增值" 2 * 2 = 4",检查条件为" 4 <20"为真,则打印值。
依此类推,直到条件返回假值为止。

Java SE 9's iterate() = Java SE 8's iterate() + Java SE 8's filter()

Java SE 8:IntStream迭代和过滤器示例:

jshell> IntStream.iterate(2, x -> x * x).filter(x -> x < 20).forEach(System.out::println)
2
4
16

Java SE 9:Nullable方法的流API

在Stream API中,ofNullable()返回包含单个元素的顺序Stream(如果非null),否则返回空Stream。

Java SE 9示例:

jshell> Stream<Integer> s = Stream.ofNullable(1)
s ==> java.util.stream.ReferencePipeline$Head@1e965684

jshell> s.forEach(System.out::println)
1

jshell> Stream<Integer> s = Stream.ofNullable(null)
s ==> java.util.stream.ReferencePipeline$Head@3b088d51

jshell> s.forEach(System.out::println)

jshell>

注意:-Stream的子接口(如IntStream,LongStream等)继承了所有这4种新方法。