Я недавно читал об этом и видел людей, использующих этот класс, но почти во всех случаях использование null
также сработало бы, если не более интуитивно. Может ли кто-нибудь привести конкретный пример, где можно Optional
было бы достичь чего-то, чего null
не удалось бы, или более простым способом? Единственное, что я могу придумать, - это использовать его с Maps
не принимаемыми null
ключами, но даже это можно сделать с помощью бокового «сопоставления» нулевого значения. Может ли кто-нибудь предоставить мне более убедительный аргумент? Спасибо.
89
Ответы:
Член команды Guava здесь.
Вероятно, самым большим недостатком
null
является то, что неясно, что он должен означать в любом данном контексте: у него нет иллюстративного названия. Не всегда очевидно, что этоnull
означает «нет значения для этого параметра» - черт возьми, в качестве возвращаемого значения иногда это означает «ошибку», или даже «успех» (!!), или просто «правильный ответ - ничего».Optional
часто это понятие, которое вы имеете в виду, когда делаете переменную допускающей значение NULL, но не всегда. Если это не так, мы рекомендуем вам написать свой собственный класс, похожий на,Optional
но с другой схемой именования, чтобы прояснить, что вы на самом деле имеете в виду.Но я бы сказал, что самое большое преимущество
Optional
не в удобочитаемости: преимущество в его защищенности от идиотов. Это заставляет вас активно думать об отсутствующем случае, если вы хотите, чтобы ваша программа вообще компилировалась, поскольку вам нужно активно развернутьOptional
и обработать этот случай. Null позволяет легко забыть о чем-то, и хотя FindBugs помогает, я не думаю, что он решает проблему почти так же. Это особенно актуально, когда вы возвращаете значения, которые могут или не могут быть «присутствующими». У вас (и других) гораздо больше шансов забыть, чтоother.method(a, b)
может возвращатьnull
значение, чем вы, вероятно, забудете, чтоa
могло бы бытьnull
при реализацииother.method
. ВозвращениеOptional
делает невозможным для вызывающих забыть этот случай, поскольку они должны сами развернуть объект.По этим причинам мы рекомендуем использовать
Optional
в качестве возвращаемого типа для ваших методов, но не обязательно в аргументах вашего метода.(Это, кстати, полностью взято из обсуждения здесь .)
источник
Map
возвращается,null
если ключ не сопоставлен, но помните, что если вы это сделаетеmap.put(key, null)
, тоmap.containsKey(key)
вернется,true
ноmap.get(key)
вернетсяnull
.Optional
может быть удобно при прояснении различия между случаем «явно сопоставлено с нулевым значением» и случаем «не присутствует в сопоставлении». ЯOptional
допускаю, что этим можно злоупотреблять, но я еще не уверен, что описанный вами случай является злоупотреблением.Optional<T>
это что «найдено, но не действует» значение. Или, точнее,Optional<T>
это способ украсить любой типT
дополнительным значением «найдено, но недействительно» - создать новый тип путем объединения двух существующих типов. Если у вас есть сотня классов, то создание отдельного значения «найдено, но недействительно» для каждогоOptional<T>
из них может оказаться беспорядочным, но это может легко работать для всех из них.Это действительно похоже на
Maybe
шаблон Monad из Haskell.Вам следует прочитать следующее, Wikipedia Monad (функциональное программирование) :
И прочитать Из необязательной к Монадам с гуавой на Блоге Kerflyn в, который обсуждается об опционной гуаве , используемых в качестве монады:
Изменить: в Java8 есть встроенный Optional, который имеет монадические операторы, такие как
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, который менее мощный.
источник
Одна из веских причин для его использования заключается в том, что он делает ваши нули очень значимыми. Вместо того, чтобы возвращать значение NULL, которое может означать множество вещей (например, ошибку, сбой, пустое значение и т. Д.), Вы можете присвоить значение NULL «имя». Взгляните на этот пример:
давайте определим базовый 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 и сделаем наши проверки с помощью Optional, чтобы он имел смысл
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()); }
таким образом, в конце концов, это способ сделать нули значимыми и уменьшить двусмысленность.
источник
Самым важным преимуществом Optional является то, что он добавляет больше деталей к контракту между исполнителем и вызывающим лицом функции. По этой причине полезен как для параметров, так и для возвращаемого типа.
Если вы сделаете соглашение, чтобы всегда иметь
Optional
для возможных нулевых объектов, вы добавите дополнительные пояснения к таким случаям, как:Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)
В контракте здесь четко указывается, что существует вероятность того, что результат не будет возвращен, но также указано, что он будет работать как при отсутствии, так
from
иto
при его отсутствии.Optional<Integer> maxPrime(Optional<Integer> from, Integer to)
В контракте указано, что from является необязательным, поэтому отсутствующее значение может иметь особое значение, например, начало с 2. Я могу ожидать, что нулевое значение
to
параметра вызовет исключение.Таким образом, хорошая часть использования Optional заключается в том, что контракт стал как описательным (аналогично
@NotNull
аннотации), так и формальным, поскольку вы должны написать код,.get()
чтобы справиться с нимOptional
.источник