Pull to refresh

Comments 19

Пустые объекты не являются подходящим инструментом для этой работы. Если ситуация исключительная, вы должны выбрасывать исключение

Между прочим это один из кейсов негативного влияния checked exceptions. Если бы RemoteInvocationException не был бы задекларирован как checked, программист бы скорей всего не допустил ошибки. Вообще по эксепшнам можно отдельно статью писать. Смысл простой по возможности избегайте checked-exceptions. Всегда врапьте checked-exceptions по возможности в один из стандатрных форм RuntimeException: IllegalArgumentException, IllegalStateException, etc...


Пользуйтесь наиболее специфическими типами данных

Более того, в некоторых случаях имеет смысл использовать класс-враппер над типом, вместо самого типа. Например, вместо String phoneNumber лучше сделать враппер-класс PhoneNumber с единственным полем String value. Для перечислимых типов по возможности используйте enums.


Используйте Optional вместо Null

Сомнительная рекомендация. Optional к Java прикрутили сбоку совсем недавно с приходом элементов функционального программирования, и его использование не должно выходить за рамки функционального "однострочника". Кроме того большинство библиотек и спецификация Java Beans не предусматривает использование Optional вообще. Для null-checking уже давно имеются @Nullable аннотации, которые являются лучшей альтернативой, нежели Optional. Благо тулинг их понимает из коробки. Если же хотите писать в труЪ функциональном стиле с монадами Try и Option, используйте замечательную библиотеку http://www.vavr.io/


Добавлю от себя еще некоторые правила:


  • По возможности используйте immutable-объекты. Их состояние детерминировано в любой момент.
  • Насчет пустых объектов: они всегда являются лучшей альтернативой, нежели nullable. Особенно важно для коллекций: возвращайте Collections.emptyList() вместо null. Для String использование по дефолту пустой строки "" вместо null избавить от кучи ненужных проверок.
  • Для collection-полей неплохой практикой будет возвращать в геттере Stream вместо Collection.
Особенно важно для коллекций: возвращайте Collections.emptyList() вместо null.

Мотивация у этого предложения та же, что у рекомендации использовать Optional?


Для collection-полей неплохой практикой будет возвращать в геттере Stream вместо Collection.

I'm a lazy girl, in a lazy world? :)

Особенно важно для коллекций: возвращайте Collections.emptyList() вместо null.
Мотивация у этого предложения та же, что у рекомендации использовать Optional?

На мой взгляд возвращать Optional имеет смысл когда в результате действия мы можем ничего не вернуть. Если говорить о коллекциях — нам есть разница пустая коллекция или "ничего" (тоже самое касательно строки, пустая строка — может быть валидным результатом). Так как пустая коллекция сама по себе тоже может быть результатом. При этом нельзя рассматривать пустой Optional как ошибку выполнения.

На мой взгляд возвращать Optional имеет смысл когда в результате действия мы можем ничего не вернуть.

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


if (str != null) {
    result += str.replace('s','f');
}

а писать так


 result += optional.map(s -> s.replace('s','f')).orElseGet("");

NPE исключен


А в случае с листами — если мы уверены, что коллекция никогда не null — можно не делать проверку перед тем, как итерироваться по ней. Идея в общем та же.

Не совсем понимаю чем вторая запись лучше и понятней первой. Если str объявлен как @Nullable, то при возможном NPE тулинг выдаст варнинг — и этого в большинстве случаев достаточно. Кроме того, тулинг достаточно умный, чтобы выводить @Nullable по коду.


Кроме того, в данном случае, как я и говорил, имеет смысл вообще использовать @Nonnull String str = "" вместо null или Optional. И никаких проверок делать не надо.


NPE исключен

Да ладно?


Optional<String> calculate() {
    return null;
}
Optional<String> str = calculate();
...
NPE исключен

Да ладно?



И ведь не поспоришь… С другой стороны по уму Optional не может быть null никогда. Это можно использовать при создании правил статического анализа кода.

Если у нас есть сложная операция или композиция, валидным результатом которой может быть "отсутствие результата", то Optional может подходить. Пример: Optional findPerson(query). Использовать же Optional для хранения или передачи состояния — плохая практика. То есть поля объекта Optional или Optional-параметр в сеттере — это сразу плохо (даже Idea вам об этом скажет). Поэтому единственный юзкейс — возврат значения, которого может не быть. Однако Optional в Java — достаточно лимитированная монада. По-сути единственное, что можно с ней сделать — это orElseXXX() (а много логики в map не запихнешь), никакой дальнейшей композиции с ней сделать нельзя (в Java 9 ей добавили свойства стрима и теперь можно делать flatMap()). Кроме того, в большинстве случаев логика требует нечто большее, чем orElse, поэтому все-равно приходится ставить if (maybe.isPresent()). Так что на мой взгляд, не фиг функционально выпендриваться на нефункциональном языке — в Java есть аннотация @Nullable.
Насчет коллекций — формально да, но реально сложно найти пример, где бы необходимо было именно Nullable-коллекция. Пустая коллекция — это и есть отсутствие результата. Какой смысл при этом будет иметь возврат null (или Optional) не совсем ясно.

Действительно, с коллекцией я перемудрил. Что-то в голову не приходит когда вместо пустой коллекции была бы необходимость вернуть null.
>Поэтому единственный юзкейс — возврат значения, которого может не быть
всмысле optional логическая абстракция чтобы сказать что тут значения может не быть и это нормально…
так null то же яйцо вид сбоку
и его использование не должно выходить за рамки функционального «однострочника


Не согласен. Если Вы не пишете на Котлине, на котором явно можно сказать, что значение не может быть Null, то очень удобно с помощью Optional явно давать понять — может это значение есть, а может быть его и нет
UFO just landed and posted this here
Если у вас где-то в коде перехват рантайм экцепшнов, то а) у меня для вас плохие новости б) это меньшая из ваших проблем
UFO just landed and posted this here

Последний совет по поводу unlift без объяснения вообще непонятен.
Вот эта конструкция


CompletableFuture<T> method(CompletableFuture<S> param)

По идее возвращает фьючу, которая инкапсулирует результат процесса, который произойдёт после того, как закончится фьюча во входном параметре.
То есть, с учётом рекомендации автора нужно писать не так


CompletableFuture<Stiring> future = method(param);

А вот так


CompletableFuture<Stiring> future = param.thenApply(method);

С листами не


List<String> list =  method(param);

а


List<String> list = list.stream.map(method).collect(Collectors.toList());

С Optional история видимо другая. Автор просто не хочет передавать Optional в качестве параметра. Тут видимо вместо.


String res = method(optional);

предлагается


String res = method(optional.getOrElse("default value"));
// This method is clearly doing two things, it should be two methods

Почему тогда 2 метода с одинаковым именем?
язык не «со строковой типизацией» а «со строгой типизацией»
Рекомендация 1: Выбрасывайте исключения, если что то идет не так

Отслеживайте исключения, когда что-то идет не так.
Не следует рушить приложение и терять все данные или выбрасывать кишки наружу.
Если что-то пошло не так, запишите это в лог, а пользователю выдайте либо вежливое сообщение об ошибке, либо просто верните результат по умолчанию (пустой список из примера).
Хм, а раз вы переводите, то наверное надо и комментарии в коде переводить.
Sign up to leave a comment.