Должны ли геттеры Java 8 возвращать необязательный тип?



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



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

664   5  

5 ответов:

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

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

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

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

(публичное объявление: никогда вызов Optional.get Если вы не можете доказать, что это никогда не будет null; вместо этого используйте один из безопасных методов, таких как orElse или ifPresent. Оглядываясь назад, мы должны были позвонить get что-то вроде getOrElseThrowNoSuchElementException или что-то, что сделало его гораздо яснее, что это был очень опасный метод, который подорвал всю цель Optional в первую очередь. Урок. (Обновление: Java 10 имеет Optional.orElseThrow(), что семантически эквивалентно get(), но чье имя больше подходит.))

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

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

Я нашел этот отрывок из Java 8 необязательно: как его использовать

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

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

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

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

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

причина Optional был добавлен в Java, потому что это:

return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .findFirst()
    .getOrThrow(() -> new InternalError(...));

чище, чем этот:

Method matching =
    Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .getFirst();
if (matching == null)
  throw new InternalError("Enclosing method not found");
return matching;

Я хочу сказать, что необязательно было написано Для поддержки функционального программирования, который был добавлен в Java в то же время. (Пример приходит любезно блог Брайана Гетца. Лучший пример может использовать orElse() метод, так как этот код будет выдавать исключение в любом случае, но вы получите картину.)

но теперь, люди используют опционально по совершенно другой причине. Они используют его для устранения недостатка в языковом дизайне. Недостаток заключается в следующем: нет способа указать, какие из параметров API и возвращаемых значений могут быть null. Это может быть упомянуто в javadocs, но большинство разработчиков даже не пишут javadocs для своего кода, и не многие будут проверять javadocs, когда они пишут. Таким образом, это приводит к большому количеству кода, который всегда проверяет нулевые значения перед их использованием, хотя они часто не могут возможно, будет null, потому что они уже были проверены повторно девять или десять раз в стеке вызовов.

Я думаю, что была реальная жажда решить этот недостаток, потому что так много людей, которые видели новый необязательный класс, предполагали, что его цель-добавить ясность в API. Вот почему люди задают такие вопросы как "геттеры должны возвращать опции?- Нет, вероятно, не должны, если только вы не ожидаете, что геттер будет использоваться в функциональном программировании, что очень маловероятно. На самом деле, если вы посмотрите, где Необязательно используется в Java API, это в основном в потоковых классах, которые являются ядром функционального программирования. (Я не проверил очень тщательно, но классы потока могут быть только место, где они используются.)

если вы планируете использовать геттер в немного функциональном коде, было бы неплохо иметь стандартный геттер и второй, который возвращает необязательный.

О, И если вам нужно, чтобы ваш класс был сериализуемым, вы абсолютно не должны использовать Необязательный.

Optionals-очень плохое решение для недостатка API, потому что a) они очень многословны, и b) они никогда не предназначались для решения этой проблемы в первую очередь.

гораздо лучшим решением проблемы API является Nullness Checker. Это обработчик аннотаций, который позволяет указать, какие параметры и возвращаемые значения могут быть null, аннотируя их с помощью @Nullable. Таким образом, компилятор может сканировать код и выяснить, если значение это может быть на самом деле null передается в значение, где null не допускается. По умолчанию предполагается, что ничто не может быть null, если оно не аннотировано так. Таким образом, вам не придется беспокоиться о нулевых значений. Передача нулевого значения параметру приведет к ошибке компилятора. Проверка объекта на null, который не может быть null, создает предупреждение компилятора. Результатом этого является изменение NullPointerException из ошибки времени выполнения в ошибку времени компиляции.

это меняет всё.

что касается ваших геттеров, не используйте опционально. И попробуйте создать свои классы так, чтобы ни один из членов не мог быть null. И, возможно, попробуйте добавить проверку Nullness в свой проект и объявить ваши геттеры и параметры setter @Nullable, если им это нужно. Я делал это только с новыми проектами. Вероятно, он создает много предупреждений в существующих проектах, написанных с большим количеством лишних тестов для null, поэтому его может быть сложно модернизировать. Но он также будет ловить много жуки. Я люблю это. Мой код намного чище и надежнее из-за этого.

(есть также новый язык, который обращается к этому. Kotlin, который компилируется в байтовый код Java, позволяет указать, может ли объект быть нулевым при его объявлении. Это более чистый подход.)

добавление к оригинальному сообщению (версия 2)

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

имейте в виду, что методы, которые предназначены для функционального программирования, и которые требуют функция ссылка, будет (и должна) быть написана в двух формах, одна из которых использует необязательный. Например, Optional.map() и Optional.flatMap() оба берут ссылки на функции. Первый принимает ссылку на обычный геттер, а второй принимает тот, который возвращает необязательный. Таким образом, вы не делаете никому одолжение, возвращая необязательное значение, где значение не может быть null.

сказав Все это, я все еще вижу подход, используемый Nullness Checker это лучший способ борьбы с нулями, так как они превращаются Возникновению исключительных ситуаций типа NullPointerException во время выполнения ошибки Ошибки времени компиляции.

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

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

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

Comments

    Ничего не найдено.