Ява.утиль.Объекты vs необязательно, что предпочтительнее?

на java.утиль.Объекты класс был расширен с помощью ряда новых методов

объекты#requireNonNullElse

соответственно

объекты#requireNonNullElseGet() на Java-9.

оба вернут первый аргумент, если он не равен null и в противном случае возвращает ненулевой второй аргумент или ненулевое значение поставщика.get ()

jshell> String nullStr = null;
nullStr ==> null

jshell> Objects.requireNonNullElse(nullStr,"lorem ipsum");
 ==> "lorem ipsum"

jshell> Objects.requireNonNullElseGet(nullStr,() -> "lorem ipsum");
 ==> "lorem ipsum"

но новый функциональность перекрывается с уже существующей в Optional класс необязательно#orElse и необязательно#orElseGet

jshell> Optional.ofNullable(nullStr).orElse("lorem ipsum");
 ==> "lorem ipsum"

jshell> Optional.ofNullable(nullStr).orElseGet(() -> "lorem ipsum");
 ==> "lorem ipsum"

единственная разница между новыми методами в Objects и тегом Optional методы - это второй аргумент или значение поставщика должно быть ненулевым в противном случае Objects закидываем NPE:

jshell> Objects.requireNonNullElseGet(nullStr,() -> null);
|  java.lang.NullPointerException thrown: supplier.get()
|        at Objects.requireNonNull (Objects.java:246)
|        at Objects.requireNonNullElseGet (Objects.java:321)
|        at (#15:1)

jshell> Objects.requireNonNullElse(nullStr,null);
|  java.lang.NullPointerException thrown: defaultObj
|        at Objects.requireNonNull (Objects.java:246)
|        at Objects.requireNonNullElse (Objects.java:301)
|        at (#16:1)

и Optional

jshell> Optional.ofNullable(nullStr).orElse(null);
 ==> null

jshell> Optional.ofNullable(nullStr).orElseGet(() -> null);
 ==> null
  • Почему разработчики JDK не обновили существующие методы в опционном класс?
  • почему они не ввели новый метод (который будет брошен NPE, если второй аргумент равен null) необязательному классу?
  • что мы должны использовать теперь необязательно или объекты?
  • делают ли новые методы объекты более предпочтительными, чем необязательными, поскольку они бросит NPE сразу и не позже где-нибудь в коде как с необязательным?

если у меня есть легаси код, что-то вроде:

String str = null; 
String result = str == null ? "other string" : str;

это просто простая проверка внутри метода. И я хотел бы повторно фактором его с использованием новейших языковых средств. Теперь, имея в виду разницу между Optional.orElse и Objects.requireNonNullOrElse что предпочтительнее?

result = Optional.ofNullable(str).orElse("other string");

или

result = Objects.requireNonNullOrElse(str,"other string);

5 ответов


самый короткий ответ на ваш вопрос "что предпочтительнее?"является любимым разработчиком всех времен "это зависит", потому что Objects::requireNonNullElse и Optional охватывают различные варианты использования.

Две Альтернативы

прежде чем ответить на ваши вопросы, я хочу рассказать вам о двух альтернативах.

Objects::requireNonNullElse

Objects::requireNonNull гарантирует, что результат вызова никогда не будет нулевым (отсюда и имя). Он обычно используется для краткой проверки конструктор или метод аргументов и позволяет читателям проверить с первого взгляда, что переменная, которой назначено возвращаемое значение не может быть null.

так что это было бы не только странно для Objects::requireNonNullElse чтобы вдруг позволить null, это также было бы бесполезно, потому что:

// if requireNonNullGet would allow null as second argument,
// the following is true for all x (including null)
Objects.requireNonNullElse(x, null) == x

вы можете утверждать, что это отличается для requireNonNullElseGet потому что это может вызвать функцию, которая в зависимости от какого-либо государства, может вернуть null или нет. Это правда, и я предполагаю, что это было считается, но requireNonNull... API было бы очень странно, если бы один из трех случаев мог фактически позволить конечному результату вызова быть null хотя имя говорит требуется non null.

Optional

Optional разработан в качестве аргумента возврата в случаях, когда returning null очень вероятно, что вызовет NPEs (например, для Streamтерминальная деятельность, где она сперва была использована). Хотя некоторые разработчики предпочитают использовать его в больше случаев (сравните Стивен Коулберн это и мой строгий подход) никто не предлагает использовать его, как в вашем демонстрации:

Optional.ofNullable(nullStr).orElse(null);
Optional.ofNullable(nullStr).orElseGet(() -> null);

Optional - это способ выразить в системе типов, что что-то может отсутствовать - это не означает, как альтернативу if-null-проверяет. В этом смысле orElse или orElseGet являются бэкдоры из Optional назад в мир nullable типов и иногда null это просто то, что вы хотите использовать, если чего-то нет, поэтому имеет смысл для них принять null в качестве аргумента (или результат поставщика).

Вопросы

теперь у нас есть то, что нам нужно, чтобы ответить на ваши вопросы:

Почему разработчики JDK не обновили существующие методы в необязательном классе?

концептуально это шло бы против чего Optional следует использовать для. Но, как уже упоминали другие, это было бы обратным несовместимое изменение как вызовы orElse(null) внезапно бросил бы исключения.

почему они не ввели новый метод (который будет брошен NPE, если второй аргумент равен null) в необязательный класс?

API расширяются только в том случае, если можно ожидать значительных улучшений существующего кода. Здесь я этого не вижу. Во многих случаях orElse получает аргумент, который вызывающий объект создает специально в качестве альтернативы для пустых optionals-редко возникает необходимость сделать дополнительную проверку, чтобы убедиться, что это не null. Если вам действительно нужно, позвоните orElse(requireNonNull(x)).

что мы должны использовать теперь необязательно или объекты?

если у вас есть переменная (будь то локальная, аргумент или поле), и вы хотите убедиться, что это не null, используйте Objects. Если вы хотите вернуть что-то, что может быть null оборачивать его в Optional. Будьте подозрительны к коду, который создает Optional (в отличие от получения одной формы вызова) и разворачивает его на конец той же цепи.

новые методы делают объекты более предпочтительными, чем необязательными, поскольку они будут бросать NPE немедленно, а не позже где-то в коде, как с необязательным?

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

если у меня есть легаси код, что-то вроде:

String str = null; 
String result = str == null ? "other string" : str;

наверняка Objects.requireNonNullOrElse(str,"other string); и рассмотреть возможность использования статического импорта, чтобы сделать его более читабельным.


Почему разработчики JDK не обновили существующие методы в необязательном классе?

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

почему они не ввели новый метод (который будет брошен NPE, если второй аргумент равен null) в необязательный класс?

вероятно, потому что это сделало бы API более запутанным и раздутые без существенного преимущества. Вы все равно можете обернуть результат requireNonNull, если хотите убедиться, что ваш код не возвращает null неожиданно.

что мы должны использовать теперь необязательно или объекты?

Если вам нужно извлечь значение из необязательного возвращаемого методом, используйте метод Optional. Если необходимо обеспечить соблюдение предварительных условий для аргумента метода, который не должен быть null, используйте Object.requireXxx. Дизайнеры с JDK никогда не выступали за использование Optional только для обертывания значения и проверки на null. Необязательно для возвращаемых значений.

новые методы делают объекты более предпочтительными, чем необязательными, поскольку они будут бросать NPE немедленно, а не позже где-то в коде, как с необязательным?

см. предыдущие пункты: вы не используете эти методы, чтобы сделать то же самое.


дело в том, что эти две сигнатуры метода являются явно другое:

public static <T> T requireNonNullElse(T obj, T defaultObj)

и

public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)

на javadoc для второго метода читает:

возвращает первый аргумент, если он не равен null и в противном случае возвращает ненулевое значение поставщика.получить.)(

другими словами: он использует что вы предоставляете здесь.

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

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

о использование Optionals - имейте в виду, что их main цель должна была использоваться для возвращаемых типов; не как параметры метода (см. здесь для дальнейшего чтения).

затем: обновление существующие методы в классе, поставляемом "в поле", почти всегда не идут. Вы абсолютноне хотите изменить семантику чего-то, что уже открыто и используется вашими клиентами; предполагая определенную семантику.


Q. Почему разработчики JDK не обновили существующие методы в необязательном классе?

А., Так Как Optional класс был разработан, чтобы избежать NPE.

Q. почему они не ввели новый метод (который будет брошен NPE, если второй аргумент равен null) в необязательный класс?

А. Один и тот же ответ.

Q. что мы должны использовать теперь опционное или объекты?.

А. Оба. Objects для простой проверки" не null " и Optional для цепочки операций, таких как map, flatMap, `фильтр'.

Q. новые методы делают объекты более предпочтительными, чем необязательными, поскольку они будут бросать NPE немедленно, а не позже где-то в коде, как с необязательным?

А. зависит от ситуации. Если у вас уже есть необязательное возвращаемое значение некоторого метода, то предпочтительнее использовать необязательное.


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

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