繁体   English   中英

Java的Collectors.toSet()是否保证允许空值?

[英]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.mergeJDK-8040892 ,另请参阅此答案 ),但故意拒绝收集器代码中的null值,与先前版本行为兼容。 仅仅因为从未说过故意未指定null行为。

因此, Collectors.toSet() (以及同样的Collectors.toList() )现在允许两个主要Java版本的null值,并且没有规范说你不能认为这是理所当然的,所以你可以确定这不会改变未来。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM