问题 (已链接)BlockingQueue.put(null)抛出NullPointerException


我已经检查了实现,它是故意这样做的

 public void put(E e) throws InterruptedException {
     if (e == null) throw new NullPointerException();

这种惊喜对于用户来说并不方便(例如,他想以这种方式用信号通知流的结尾)并打破与集合的一般契约,这很容易接受null元素。 BlockingQueue区分null元素有什么意义?如果空值如此糟糕,我们可能应该根本不使用它们并在JLS中强制执行此低值?


9366
2018-05-31 09:13


起源



答案:


接受空值是  的一部分 Collection 合同。的确如此 Collection  的Javadoc 具体说明:

某些集合实现对它们可能包含的元素有限制。例如,某些实现禁止null元素,并且一些实现对其元素的类型有限制。尝试添加不合格的元素会引发未经检查的异常,通常是NullPointerException或ClassCastException。

在很多情况下,添加 null 收集意味着你的程序中有一个错误,而不是你故意把它放进去。例如,Guava库(我参与其中) 做出明确的决定 从许多集合实现中拒绝null,特别是不可变的集合:

我们对Google的内部代码库进行了详尽的研究,结果表明,大约5%的时间内,集合中允许使用null元素,而其他95%的情况最好通过在null上快速失败来实现。

通常有解决方法  接受空值,但许多集合实现决定拒绝空值(大多数用户认为有用,因为它可以帮助他们找到错误)并为显式空值适当的罕见情况提供解决方法。

老实说,我认为原因 LinkedBlockingQueue 在这个类别中,当开发原始集合框架时,所有这些都没有被弄清楚,但是在添加并发集合时非常清楚。 Doug Lea,他做了很多工作 util.concurrent,有人引述说,

Null糟透了。

在最坏的情况下,对象包装器或“毒物对象”始终是有效的解决方法;番石榴提供了一个 Optional 在许多情况下可以发挥作用的类,这是广泛讨论的 这里 在StackOverflow上。


12
2018-05-31 09:15



好吧,BlockingQueue中有什么特别需要它来阻止空值?如果没有,那么为什么其他收藏品不这样做呢? - Val
你说“在很多情况下,将null添加到集合意味着你的程序中存在一个错误”。我怀疑空集出现在集合中,从具有空值的局部变量读取。程序中的任何空值都表示错误。这就是为什么建议在JLS中完全禁止空值。 - Val
问题是无法完全禁止空值。除了完全打破向后兼容性(Sun和Oracle已经完成了 异常 小心不要这样做,即使它意味着在Java中保留明显的错误和错误的库),你也无法避免它在例如对象数组上:当你说 new String[5]如果不是,那么阵列还会填充什么呢? null?这是令人不快的,但即使我们想要,也不清楚我们是否可以摆脱它。 - Louis Wasserman
当然不是收藏品,但我们不能完全删除 阵列 来自Java语言。此外,许多集合实现在内部使用数组。总而言之,有 语言 在JVM上运行,实际上是禁止的 null。即使我们无法在Java中更改它,其他语言也可以并且确实禁止null。 - Louis Wasserman
没有人禁止任何事情。图书馆开发人员正在制作它 稍微困难一些 例如使用空值,所以你不要在没有意义的情况下射击自己,但仍有解决方法。 (我不了解你,但我很高兴我使用的语言难以或不可能出现段错误,即使C或C ++专家可以编写通常不会出现段错误的程序;它更多或者不太相同的原则。) - Louis Wasserman


答案:


接受空值是  的一部分 Collection 合同。的确如此 Collection  的Javadoc 具体说明:

某些集合实现对它们可能包含的元素有限制。例如,某些实现禁止null元素,并且一些实现对其元素的类型有限制。尝试添加不合格的元素会引发未经检查的异常,通常是NullPointerException或ClassCastException。

在很多情况下,添加 null 收集意味着你的程序中有一个错误,而不是你故意把它放进去。例如,Guava库(我参与其中) 做出明确的决定 从许多集合实现中拒绝null,特别是不可变的集合:

我们对Google的内部代码库进行了详尽的研究,结果表明,大约5%的时间内,集合中允许使用null元素,而其他95%的情况最好通过在null上快速失败来实现。

通常有解决方法  接受空值,但许多集合实现决定拒绝空值(大多数用户认为有用,因为它可以帮助他们找到错误)并为显式空值适当的罕见情况提供解决方法。

老实说,我认为原因 LinkedBlockingQueue 在这个类别中,当开发原始集合框架时,所有这些都没有被弄清楚,但是在添加并发集合时非常清楚。 Doug Lea,他做了很多工作 util.concurrent,有人引述说,

Null糟透了。

在最坏的情况下,对象包装器或“毒物对象”始终是有效的解决方法;番石榴提供了一个 Optional 在许多情况下可以发挥作用的类,这是广泛讨论的 这里 在StackOverflow上。


12
2018-05-31 09:15



好吧,BlockingQueue中有什么特别需要它来阻止空值?如果没有,那么为什么其他收藏品不这样做呢? - Val
你说“在很多情况下,将null添加到集合意味着你的程序中存在一个错误”。我怀疑空集出现在集合中,从具有空值的局部变量读取。程序中的任何空值都表示错误。这就是为什么建议在JLS中完全禁止空值。 - Val
问题是无法完全禁止空值。除了完全打破向后兼容性(Sun和Oracle已经完成了 异常 小心不要这样做,即使它意味着在Java中保留明显的错误和错误的库),你也无法避免它在例如对象数组上:当你说 new String[5]如果不是,那么阵列还会填充什么呢? null?这是令人不快的,但即使我们想要,也不清楚我们是否可以摆脱它。 - Louis Wasserman
当然不是收藏品,但我们不能完全删除 阵列 来自Java语言。此外,许多集合实现在内部使用数组。总而言之,有 语言 在JVM上运行,实际上是禁止的 null。即使我们无法在Java中更改它,其他语言也可以并且确实禁止null。 - Louis Wasserman
没有人禁止任何事情。图书馆开发人员正在制作它 稍微困难一些 例如使用空值,所以你不要在没有意义的情况下射击自己,但仍有解决方法。 (我不了解你,但我很高兴我使用的语言难以或不可能出现段错误,即使C或C ++专家可以编写通常不会出现段错误的程序;它更多或者不太相同的原则。) - Louis Wasserman