(链接)BlockingQueue.put(null) thrownullPointerException

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

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

这种惊喜对于用户来说并不方便(例如,他们希望以这种方式发出流结束的信号),并且打破了集合的一般契约,集合很容易接受空元素。BlockingQueue 区分 null 元素的意义何在?如果 nulls 如此糟糕,那么我们是否应该完全避免使用它们,并在 JLS 中强制执行此低值?


答案 1

接受 null 不是协定的一部分。事实上,Javadoc特别指出:CollectionCollection

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

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

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

通常有一些解决方法可以接受 null,但许多集合实现会决定拒绝 null(大多数用户认为这很有帮助,因为它可以帮助他们找到 bug),并为适合显式 null 的极少数情况提供解决方法。

老实说,我认为属于这一类别的原因是,在开发原始集合框架时,所有这些都没有被弄清楚,但是当添加并发集合时,已经很清楚了。道格·李(Doug Lea)做了大部分工作,他被引述说:LinkedBlockingQueueutil.concurrent

空很糟糕。

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


答案 2