我已经检查了这个实现,它是有意为之的。
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
这种惊喜对用户来说不方便(例如,想要以此方式发出流结束信号的用户),并破坏了与集合的一般契约,后者很容易接受空元素。BlockingQueue区分空元素的意义何在?如果null值如此糟糕,我们可能应该完全避免使用它们,并在JLS中执行此操作吗?
我已经检查了这个实现,它是有意为之的。
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
这种惊喜对用户来说不方便(例如,想要以此方式发出流结束信号的用户),并破坏了与集合的一般契约,后者很容易接受空元素。BlockingQueue区分空元素的意义何在?如果null值如此糟糕,我们可能应该完全避免使用它们,并在JLS中执行此操作吗?
接受null值并非Collection合同的一部分。实际上,Collection的Javadoc明确指出:
某些集合实现对它们所包含的元素有限制。例如,某些实现禁止空元素,而有些则对其元素类型有限制。尝试添加不合格的元素会抛出未检查的异常,通常是NullPointerException或ClassCastException。
在许多情况下,向集合中添加null
意味着您的程序中存在错误,而不是故意放置它。例如,我贡献代码的Guava库做出了明确的决定,拒绝在许多集合实现中包含null值,特别是不可变的集合实现:
我们对Google内部代码库进行了详尽的研究,发现空元素在约5%的情况下允许存在于集合中,而其他95%的情况最好快速失败以避免null值。
通常有一些解决方法可以接受空值,但是许多集合实现决定拒绝空值(这对大多数用户来说很有帮助,因为它们能够帮助他们找到错误),并为明确的空值提供解决方法,以应对罕见情况。
老实说,我认为LinkedBlockingQueue
之所以属于这个类别,是因为当最初开发集合框架时还没有想清楚这一点,但是在添加并发集合时已经非常明确了。Doug Lea是util.concurrent
的主要开发者之一,他曾经说过:
空值很糟糕。
在最坏的情况下,对象包装器或“毒药对象”始终是有效的解决方法;Guava提供了一个Optional
类,在许多情况下可以担任该角色,这在StackOverflow上得到了广泛讨论here。
new String[5]
时,如果不是null
,那么数组会填充什么?这很不愉快,但即使我们想要摆脱它,也不清楚我们能否做到。 - Louis Wassermannull
。即使我们无法在Java中更改它,其他语言也可以并且确实禁止null。 - Louis Wassermanpoll(long timeout, TimeUnit unit)
使用null
来表示超时发生。如果该类代替此目的使用TimeoutException
,允许null
值可能是可以的,但事实并非如此。 - JHH