Недавно я прочитал об этом и увидел людей, использующих этот класс, но в большинстве случаев использование null
также сработало бы - если не более интуитивно. Может ли кто-нибудь предоставить конкретный пример, где Optional
достигнет чего-то, что null
не может или намного более чистым способом? Единственное, что я могу придумать, это использовать его с Maps
, которые не принимают ключи null
, но даже это можно сделать с боковым "отображением" нулевого значения. Может ли кто-нибудь дать мне более убедительный аргумент? Спасибо.
Какой смысл в классе Guava Option
Ответ 1
Член команды Guava здесь.
Вероятно, самым большим недостатком null
является то, что он не является очевидным, что он должен понимать в любом конкретном контексте: он не имеет иллюстративного имени. Не всегда очевидно, что null
означает "нет значения для этого параметра" - heck, как возвращаемое значение, иногда это означает "ошибка" или даже "успех" (!!), или просто "правильный ответ - ничто" ". Optional
часто представляет собой концепцию, которую вы на самом деле имеете в виду, когда вы делаете переменную обнуляемой, но не всегда. Когда это не так, мы рекомендуем вам написать свой собственный класс, похожий на Optional
, но с другой схемой именования, чтобы понять, что вы на самом деле имеете в виду.
Но я бы сказал, что самое большое преимущество Optional
не в читаемости: преимущество - его идиот-доказательство. Это заставляет вас активно думать о отсутствующем случае, если вы хотите, чтобы ваша программа вообще компилировалась, так как вам нужно активно разворачивать Optional
и обращаться к этому случаю. Null делает это довольно просто, чтобы просто забыть что-то, и хотя FindBugs помогает, я не думаю, что он решает проблему почти так же хорошо. Это особенно актуально, когда вы возвращаете значения, которые могут или не могут присутствовать. Вы (и другие) гораздо более склонны забывать, что other.method(a, b)
может вернуть значение null
, чем вы, вероятно, забудете, что a
может быть null
при реализации other.method
. Возврат Optional
не позволяет вызывающим абонентам забыть этот случай, так как они должны сами разворачивать объект.
По этим причинам мы рекомендуем использовать Optional
как возвращаемый тип для ваших методов, но необязательно в аргументах метода.
(Это, кстати, полностью очерчено, из обсуждения здесь.)
Ответ 2
Это действительно выглядит как Maybe
Монограмма у Haskell.
Вы должны прочитать следующее: Wikipedia Monad (функциональное программирование):
И прочитайте От Необязательного до Монады с Guava в Блог Kerflyn,, в котором обсуждается опциональный вариант Guava, используемый в качестве монады:
Edit:
С Java8 имеется встроенный опциональный, который имеет монадические операторы типа flatMap
. Это был спорный вопрос, но, наконец, он был реализован.
См. http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html
public Optional<String> tryFindSimilar(String s) //...
Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar = opt.flatMap(this::tryFindSimilar);
Оператор flatMap
имеет важное значение для обеспечения монадических операций и позволяет легко связывать вызовы, которые все возвращают Необязательные результаты.
Подумайте об этом, если бы вы использовали оператор map
5 раз, вы получили бы Optional<Optional<Optional<Optional<Optional<String>>>>>
, а использование flatMap
дало бы вам Optional<String>
С Java8 я бы предпочел не использовать Guava Optional, который менее мощный.
Ответ 3
Одна из веских причин использовать его в том, что он делает ваши нули очень значимыми. Вместо того, чтобы возвращать нуль, что может означать много вещей (например, ошибка, или сбой, или пустой, и т.д.), Вы можете поместить "имя" в свой нуль. Посмотрите на этот пример:
позволяет определить базовое POJO:
class PersonDetails {
String person;
String comments;
public PersonDetails(String person, String comments) {
this.person = person;
this.comments = comments;
}
public String getPerson() {
return person;
}
public String getComments() {
return comments;
}
}
Теперь давайте использовать это простое POJO:
public Optional<PersonDetails> getPersonDetailstWithOptional () {
PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,
lets make the return value more meaningful*/
if (details == null) {
//return an absent here, caller can check for absent to signify details are not present
return Optional.absent();
} else {
//else return the details wrapped in a guava 'optional'
return Optional.of(details);
}
}
Теперь избегаем использования null и выполняем наши проверки с опциональным, поэтому его значимый
public void checkUsingOptional () {
Optional<PersonDetails> details = getPersonDetailstWithOptional();
/*below condition checks if persons details are present (notice we dont check if person details are null,
we use something more meaningful. Guava optional forces this with the implementation)*/
if (details.isPresent()) {
PersonDetails details = details.get();
// proceed with further processing
logger.info(details);
} else {
// do nothing
logger.info("object was null");
}
assertFalse(details.isPresent());
}
таким образом, в конце концов, это способ сделать значения null значимыми и менее двусмысленными.
Ответ 4
Важнейшим преимуществом Необязательного является то, что он добавляет более подробную информацию к контракту между разработчиком и вызывающей функцией. По этой причине они полезны для параметров и типа возврата.
Если вы делаете соглашение всегда иметь Optional
для возможных нулевых объектов, вы добавляете дополнительные пояснения к таким случаям, как:
-
Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)
Контракт здесь четко указывает, что существует вероятность того, что результат не будет возвращен, а также покажет, что он будет работать с
from
иto
как отсутствующий. -
Optional<Integer> maxPrime(Optional<Integer> from, Integer to)
Контракт указывает, что from является необязательным, поэтому значение отсутствует может иметь особое значение, такое как начало с 2. Я могу ожидать, что значение null для параметра
to
вызовет исключение.
Таким образом, хорошая часть использования Необязательного заключается в том, что контракт стал как описательным (аналогичным с аннотацией @NotNull
), так и формальным, так как вы должны написать код .get()
, чтобы справиться с Optional
.