(Связано) BlockingQueue.put(null) throws NullPointerException

Я проверил реализацию, он делает это намеренно

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

Этот сюрприз не удобен для пользователя (который хочет передать конец потока таким образом, например) и нарушает общий контракт с коллекциями, которые легко принимают нулевые элементы. Какова точка BlockingQueue для различения нулевых элементов? Если nulls являются настолько плохими, может быть, мы должны воздерживаться от их использования вообще и применять этот минимум в JLS?

Ответ 1

Принимая нули, не является частью контракта Collection. Действительно, Collection Javadoc конкретно указывает:

Некоторые реализации коллекции имеют ограничения на элементы, которые они могут содержать. Например, некоторые реализации запрещают нулевые элементы, а некоторые имеют ограничения на типы их элементов. Попытка добавления неприемлемого элемента выдает исключение, исключающее исключение, обычно NullPointerException или ClassCastException.

Во многих случаях добавление null в коллекцию означает, что в вашей программе есть ошибка, а не то, что вы ее намеренно вводили. Например, библиотека Guava (в которую я вношу свой вклад) делает явное решение отклонять нули от многих своих реализаций коллекции, в частности, неизменяемых

Мы провели исчерпывающее исследование внутренней базы кодов Google, в которой указывалось, что нулевые элементы разрешены в сборках примерно в 5% случаев, а остальные 95% случаев лучше всего обслуживаются путем быстрого отказа от нулей.

Обычно применяются обходные пути, которые принимают значения NULL, но многие реализации коллекции принимают решение отклонять нули (которые большинство пользователей считают полезными, поскольку они помогают найти ошибки) и предлагают обходные пути для редкого случая, когда явные нули являются подходящими.

Вполне честно, я думаю, что причина, по которой LinkedBlockingQueue в этой категории, заключается в том, что все это не было выяснено, когда была разработана исходная структура коллекций, но к тому времени, когда параллельные коллекции были добавляется. Даг Ли, который сделал большую часть работы над util.concurrent, был процитирован,

Null отстой.

В худшем случае обертки объектов или "ядовитые объекты" всегда являются допустимыми обходными решениями; Guava предоставляет класс Optional, который может выполнять эту роль во многих случаях, что широко обсуждается здесь в StackOverflow.