[英]Is Java’s Collectors.toSet() guaranteed to permit nulls?
Set
接口不承诺实现是否允许null
元素。 每个实现都应该在其文档中声明。
Collectors.toSet()
承诺返回的实现Set
,但明确地让“的类型,可变性,串行化,或的线程安全没有保障Set
返回”。 没有提到空安全性。
OpenJDK中的Collectors.toSet()
的当前实现总是使用HashSet
,它允许null元素,但是这可能在将来发生变化,而其他实现可能会有不同的变化。
如果Set
实现禁止null
元素,它会在不同时间抛出NullPointerException
,特别是在尝试add(null)
。 似乎如果Collectors.toSet()
决定使用null stream.collect(Collectors.toSet())
Set
实现, stream.collect(Collectors.toSet())
在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)
这样的代码来请求一个特定的集合实现。
编辑:有一个现有的问题 ,听起来表面上相似,这个问题被关闭作为一个假设的副本。 但是,链接的问题根本不涉及Collectors.toSet()
。 此外,该问题的答案构成了我的问题的基本假设 。 那个问题问:流中是否允许空值? 是。 但是当通过标准收集器收集包含空值的(完全允许的)流时会发生什么?
故意未指定的行为(如“类型,可变性,可串行性或线程安全性”)与未指定的行为(如null
支持)之间存在差异。
每当一个行为被指定时,参考实现的实际行为往往成为事实问题,即使由于兼容性约束而无法改变原始意图,或者至少在没有它的情况下也不能改变一个有力的理由。
请注意,虽然未使用返回真正不可变或不可序列化Set
的保留权限,但仅仅因为Java 8发行版中不存在此类型,即使没有足够的哈希映射类型也可以实施非null
行为,就像groupingBy
禁止null
键一样,虽然也没有说明。
进一步注意,虽然groupingBy
收集器故意拒绝其实现代码中的null
键,但toMap
是实际行为如何成为合同一部分的一个很好的例子。 在Java 8中, toMap
允许null
键但拒绝null
值,因为它调用具有该行为的Map.merge
。 看来,这首先不是预期的行为。 现在,在Java 9中,没有合并函数的toMap
收集器不再使用Map.merge
( JDK-8040892 ,另请参阅此答案 ),但故意拒绝收集器代码中的null
值,与先前版本行为兼容。 仅仅因为从未说过故意未指定null
行为。
因此, Collectors.toSet()
(以及同样的Collectors.toList()
)现在允许两个主要Java版本的null
值,并且没有规范说你不能认为这是理所当然的,所以你可以确定这不会改变未来。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.