1.概述
在本教程中,我们将学习如何从Java集合创建空安全流。
要完全理解本材料,需要对Java 8的方法引用、Lambda表达式、可选和StreamAPI有一定的了解。
如果你不熟悉这些主题中的任何一个,可以先看看这些以前的文章:Java 8中的新功能、Java8可选指南和Java 8流简介。
2.Maven依赖
在我们开始之前,我们需要一个Maven依赖项以用于某些场景:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.2</version>
</dependency>
[commons-collections4](https://search.maven.org/classic/#search | gav | 1 | g%3A”org.apache.commons”ANDa%3A”commons-collections4”)库可以从MavenCentral下载。 |
3.从集合创建流
从任何类型的Collection创建Stream的基本方法是调用集合的stream()或parallelStream()方法,具体取决于所需的流类型:
Collection<String> collection = Arrays.asList("a", "b", "c");
Stream<String> streamOfCollection = collection.stream();
我们的收藏很可能在某个时候有外部资源。当从集合中创建流时,我们可能会以类似于下面的方法结束:
public Stream<String> collectionAsStream(Collection<String> collection) {
return collection.stream();
}
这可能会导致一些问题。当提供的集合指向空引用时,代码将在运行时抛出NullPointerException。
下一节将介绍我们如何防止这种情况发生。
4.使创建的集合流成为空安全的
4.1.添加检查以防止空取消引用
为了防止意外的空指针异常,我们可以选择添加检查以防止在从集合创建流时出现空引用:
Stream<String> collectionAsStream(Collection<String> collection) {
return collection == null
? Stream.empty()
: collection.stream();
}
然而,这种方法有几个问题。
首先,空检查妨碍了业务逻辑,降低了程序的整体可读性。
其次,在JavaSE8之后,使用null来表示值的缺失被认为是错误的方法;有一种更好的方法来模拟值的缺失和存在。
请务必记住,空Collection与nullCollection不同。第一个表示我们的查询没有要显示的结果或元素,而第二个表示在此过程中刚刚发生了一种错误。
4.2.使用CollectionUtils库中的emptyIfNull方法
我们可以选择使用ApacheCommons的CollectionUtils库来确保我们的流是null安全的。这个库提供了一个emptyIfNull方法,它返回一个不可变的空集合,给定一个null集合作为参数,否则返回集合本身:
public Stream<String> collectionAsStream(Collection<String> collection) {
return emptyIfNull(collection).stream();
}
这是一个非常简单的策略;但是,它依赖于外部库。如果软件开发策略限制使用此类库,则此解决方案无效。
4.3.使用Java 8的Optional
JavaSE8的Optional是一个单值容器,它要么包含一个值,要么不包含一个值。如果缺少值,则称Optional容器为空。
使用Optional可以说是从流中创建空安全集合的最佳整体策略。
让我们看看如何使用它,然后在下面进行快速讨论:
public Stream<String> collectionToStream(Collection<String> collection) {
return Optional.ofNullable(collection)
.map(Collection::stream)
.orElseGet(Stream::empty);
}
- Optional.ofNullable(collection)从传入的集合中创建一个Optional对象。如果集合为空,则创建一个空的Optional对象。
- map(Collection::stream)提取Optional对象中包含的值作为map方法(Collection.stream())的参数。
- orElseGet(Stream::empty)在Optional对象为空的情况下返回回退值,即传入的集合为null。
因此,我们主动保护我们的代码免受意外的空指针异常。
4.4.使用Java9的StreamOfNullable
检查我们之前在4.1节中的三元示例,并考虑到某些元素可能为null而不是Collection的可能性,我们可以使用Stream类中的ofNullable方法。
我们可以将上面的例子改造成:
Stream<String> collectionAsStream(Collection<String> collection) {
return collection.stream().flatMap(s -> Stream.ofNullable(s));
}
5.总结
在本文中,我们简要讨论了如何从给定集合创建流。然后,我们继续探索三个关键策略,以确保创建的流在从集合创建时是空安全的。
最后,我们指出了在相关情况下使用每种策略的缺点。
与往常一样,本教程的完整源代码可在GitHub上获得。