Какой смысл в классе Guava Option

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

Ответ 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.