Java (链接)BlockingQueue.put(null)抛出NullPointerException

Java (链接)BlockingQueue.put(null)抛出NullPointerException,java,collections,null,nullpointerexception,Java,Collections,Null,Nullpointerexception,我已经检查了实现,它是故意这样做的 public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); 这种意外对于用户来说并不方便(例如,用户希望以这种方式发出流结束的信号),并且打破了与集合的一般约定,集合很容易接受空元素。BlockingQueue区分空元素的意义是什么?如果空值如此糟糕,我们是否应该完全避免使用它们,并在JLS中强制执行此低值

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

 public void put(E e) throws InterruptedException {
     if (e == null) throw new NullPointerException();
这种意外对于用户来说并不方便(例如,用户希望以这种方式发出流结束的信号),并且打破了与集合的一般约定,集合很容易接受空元素。BlockingQueue区分空元素的意义是什么?如果空值如此糟糕,我们是否应该完全避免使用它们,并在JLS中强制执行此低值

接受空值不是
集合
合同的一部分。实际上,
集合
明确指出:

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

在许多情况下,将
null
添加到集合中意味着程序中的某个地方存在错误,而不是故意将其放入。例如,Guava库(我参与其中)拒绝许多集合实现中的空值,特别是不可变的集合实现:

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

通常存在接受空值的变通方法,但许多集合实现决定拒绝空值(大多数用户认为这很有帮助,因为它有助于他们发现错误),并提供适合显式空值的罕见情况的变通方法

老实说,我认为
LinkedBlockingQueue
属于这一类的原因是,在开发原始集合框架时,所有这些都还没有被弄清楚,但在添加并发集合时,已经非常清楚了。Doug Lea在
util.concurrent
上做了很多工作,他说

空值很糟糕


在最坏的情况下,对象包装或“有毒对象”始终是有效的解决方法;Guava提供了一个类,在许多情况下都可以充当这个角色,这在StackOverflow上有广泛的讨论。

Ok,BlockingQueue有什么特别之处,需要它来阻止空值?如果没有,那么为什么其他集合不这样做呢?问题是空值不能被完全禁止。除了完全破坏向后兼容性(Sun和Oracle一直非常小心地避免这样做,即使这意味着在Java中保留明显的错误和糟糕的库),您也无法避免它,例如在对象数组上:当您说
新字符串[5]
,如果不是
null
,数组还会填充什么?这是令人不快的,但即使我们想摆脱它,也不清楚我们是否可以摆脱它。当然,在集合中不是这样,但我们不能从Java语言中完全删除数组。此外,许多集合实现在内部使用数组。综上所述,在JVM上运行的一些函数确实禁止
null
。即使我们不能在Java中更改它,其他语言也可以,并且确实禁止null。没有人禁止任何东西。库开发人员只是稍微增加了使用nulls的难度,所以你不会毫无意义地攻击自己,但仍然有解决办法。(我不知道你,但我很高兴我用一种语言,使它很难或不可能分割,即使C或C++中的专家可以编写程序,通常不分段;它或多或少是相同的原则。)@瓦尔FWW四年后-“什么是特殊的阻塞队列需要它来阻止零”。首先,
poll(长超时,TimeUnit)
使用
null
发出超时发生的信号。如果类使用了
TimeoutException
来实现此目的,那么允许
null
值可能会很好,但事实并非如此。