Должны ли получатели Java 8 возвращать дополнительный тип?

Optional тип, введенный в Java 8, является новой вещью для многих разработчиков.

Является ли метод getter возвращением Optional<Foo> вместо классической Foo хорошей практики? Предположим, что значение может быть null.

Ответ 1

Конечно, люди будут делать то, что хотят. Но у нас было четкое намерение при добавлении этой функции, и она не была бы общей целью "Может быть, для кого-то", поскольку многие люди хотели бы, чтобы мы это сделали. Наше намерение заключалось в том, чтобы предоставить ограниченный механизм для типов возвращаемых методов библиотечного метода, где должен быть четкий способ представления "никакого результата", а использование null для таких целей в подавляющем большинстве могло вызвать ошибки.

Например, вы, вероятно, никогда не должны использовать его для чего-то, что возвращает массив результатов или список результатов; вместо этого возвратите пустой массив или список. Вы почти никогда не должны использовать его как поле чего-то или параметра метода.

Я думаю, что регулярное использование его в качестве возвращаемого значения для геттеров определенно будет чрезмерным.

Нет ничего страшного в том, что Необязательно, что этого следует избегать, это просто не то, что многие хотели бы этого, и, соответственно, мы были довольно обеспокоены риском ревностного чрезмерного использования.

(Объявление общественной службы: НИКОГДА не вызывайте Optional.get, если вы не можете доказать, что он никогда не будет равен нулю, вместо этого используйте один из безопасных методов, например orElse или ifPresent. В ретроспективе нам нужно было бы вызвать get что-то например, getOrElseThrowNoSuchElementException или что-то, что сделало намного яснее, что это был очень опасный метод, который в первую очередь подорвал всю цель Optional. Извлеченный урок.)

Ответ 2

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

"Важно отметить, что намерение класса" Необязательно " не заменять каждую единственную нулевую ссылку. Вместо этого ее целью является разработка более понятных API так, чтобы, просто прочитав подпись метода, вы можете узнать, можете ли вы ожидать необязательное значение. Это заставляет вас активно разворачивать опцию, чтобы справиться с отсутствием значения". - Устали от Null Pointer Exceptions? Рассмотрите возможность использования Java SE 8 Дополнительно!

Я также нашел эту выдержку из Java 8 Дополнительно: как ее использовать

"Необязательный не предназначен для использования в этих контекстах, так как он ничего нам не купит:

  • в слое модели домена (не сериализуется)
  • в DTO (по той же причине)
  • во входных параметрах методов
  • в параметрах конструктора

Который также, кажется, поднимает некоторые действительные точки.

Я не смог найти никаких негативных коннотаций или красных флагов, чтобы предположить, что Optional следует избегать. Я думаю, что общая идея заключается в том, что если это поможет или улучшает удобство использования вашего API, используйте его.

Ответ 3

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

Ответ 4

Если вы используете современные сериализаторы и другие фреймворки, которые понимают Optional, то я нашел, что эти рекомендации хорошо работают при написании Entity beans и доменных слоев:

  • Если уровень сериализации (обычно БД) позволяет значение null для ячейки в столбце BAR в таблице FOO, то getter Foo.getBar() может возвращать Optional, указывая разработчику, что это значение могут разумно ожидать, что они будут нулевыми, и они должны справиться с этим. Если БД гарантирует, что значение не будет равно нулю, то геттер должен не обернуть это в Optional.
  • Foo.bar должен быть private и не быть Optional. Там действительно нет причин для Optional, если это private.
  • Установщик Foo.setBar(String bar) должен иметь тип BAR и не Optional. Если это нормально, используйте аргумент null, тогда укажите это в комментарии JavaDoc. Если не использовать null a IllegalArgumentException или некоторая подходящая бизнес-логика, то ИМХО, более уместно.
  • Конструкторам не нужны аргументы Optional (по причинам, сходным с пунктом 3). Обычно я включаю только аргументы в конструкторе, что должен быть непустым в базе данных сериализации.

Чтобы сделать это более эффективным, вы можете отредактировать свои шаблоны IDE для генерации геттеров и соответствующих шаблонов для toString(), equals(Obj o) и т.д. или использовать поля непосредственно для них (большинство генераторов IDE уже имеют дело с нулями).