【发布时间】:2017-11-09 22:48:19
【问题描述】:
Set 接口不承诺实现是否允许null 元素。每个实现都应该在其文档中声明这一点。
Collectors.toSet() 承诺返回 Set 的实现,但明确“不保证返回的 Set 的类型、可变性、可序列化性或线程安全性”。没有提到空安全。
OpenJDK 中Collectors.toSet() 的当前实现始终使用HashSet,它允许空元素,但这可能会在未来发生变化,其他实现可能会有所不同。
如果Set 实现禁止null 元素,它会在不同时间抛出NullPointerException,尤其是在尝试add(null) 期间。似乎如果Collectors.toSet() 决定使用不容忍空值的Set 实现,则在Stream stream 上调用stream.collect(Collectors.toSet()) 会抛出异常。 collect 的规范没有列出任何例外,也没有列出任何 Collector 方法的规范。这可能表明collect 调用允许stream 中的空值,但另一方面,不清楚这是否真的意味着很多,因为NullPointerException 是一个未经检查的异常,并且不必严格列出。
这在其他地方有更清楚的说明吗?特别是,下面的代码是否保证不抛出?是否保证返回true?
import java.util.stream.*;
class Test {
public static boolean setContainsNull() {
return Stream.of("A", "list", "of", null, "strings")
.collect(Collectors.toSet())
.contains(null);
}
}
如果不是,那么我假设我们应该在使用Collectors.toSet() 之前始终确保流不包含空值,或者准备好处理NullPointerException。 (但仅此异常是否足够?)或者,当这是不可接受或难以接受时,我们可以使用 Collectors.toCollection(HashSet::new) 之类的代码请求特定的集合实现。
编辑: 有一个existing question 听起来表面上相似,这个问题作为假设的重复而被关闭。但是,链接的问题根本没有解决Collectors.toSet()。此外,该问题的答案构成了我的问题的基本假设。这个问题问:流中是否允许空值?是的。 但是当包含空值的(完全允许的)流通过标准收集器收集时会发生什么?
【问题讨论】:
-
没有提到,但我认为如果它不允许空值,那将是非常糟糕的形式,并且没有说明任何内容。
-
@SleimanJneidi 您链接的问题与标准收集器无关,这就是我要问的问题。它询问流是否可以包含空值(它们确实存在,我的问题认为这是理所当然的)以及是否有任何魔法可以让明确地不容忍空值的代码应用于包含空值的流以避免 NPE(没有)。
collect(Collectors.toSet())不是明确的不容忍 null 的代码——或者如果你愿意,我只是在问它是否是。 -
由于它没有指定,我不会假设任何一种方式。如果我知道空值是可能的,我会一直使用
toCollection(HashSet::new),以确保完全安全。
标签: java java-8 null java-stream