Java.util.Objects vs Необязательный, что предпочтительнее?
Класс java.util.Objects был расширен с помощью ряда новых методов
Объекты # requireNonNullElse
соответственно
Объекты # requireNonNullElseGet() в Java-9
.
Оба возвращают первый аргумент, если он не равен null, и в противном случае возвращает ненулевой второй аргумент или ненулевое значение поставщика .get()
jshell> String nullStr = null;
nullStr ==> null
jshell> Objects.requireNonNullElse(nullStr,"lorem ipsum");
$13 ==> "lorem ipsum"
jshell> Objects.requireNonNullElseGet(nullStr,() -> "lorem ipsum");
$14 ==> "lorem ipsum"
Но новая функциональность перекрывается с уже существующим в классе Optional
Необязательный # orElse и Дополнительно # orElseGet
jshell> Optional.ofNullable(nullStr).orElse("lorem ipsum");
$17 ==> "lorem ipsum"
jshell> Optional.ofNullable(nullStr).orElseGet(() -> "lorem ipsum");
$18 ==> "lorem ipsum"
Единственное различие между новыми методами в Objects
и соответствующими методами Optional
заключается в том, что второй аргумент или значение поставщика должны быть не равными нулю, иначе Objects
throws 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);
$19 ==> null
jshell> Optional.ofNullable(nullStr).orElseGet(() -> null);
$20 ==> 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);
Ответы
Ответ 1
Самый короткий ответ на ваш вопрос "что предпочтительнее?" является любимым разработчиком "все время", потому что 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
или нет. Это правда, и я предполагаю, что это было рассмотрено, но API requireNonNull...
был бы действительно странным, если бы один из трех случаев мог фактически дать окончательный результат вызова null
, даже если имя говорит, что требуется не null.
Optional
Optional
был разработан как возвращаемый аргумент в случаях, когда возвращение null
, скорее всего, вызовет NPE (например, для Stream
терминал, где он был впервые использован). Хотя некоторые разработчики предпочитают использовать его в большем количестве случаев (сравните прагматичный подход Стивена Колеборна и мой строгий подход) никто не предлагает его использовать, как в вашей демонстрации:
Optional.ofNullable(nullStr).orElse(null);
Optional.ofNullable(nullStr).orElseGet(() -> null);
Optional
- способ выразить в системе типов что-то может отсутствовать - это не означает альтернативу if
- null
-checks. В этом смысле orElse
или orElseGet
возвращаются обратно из Optional
обратно в мир типов с нулевым значением, а иногда null
- это то, что вы хотите использовать, если что-то не существует, поэтому имеет смысл принять null
в качестве аргумента (или результата поставщика).
Ваши вопросы
Теперь у нас есть то, что нам нужно, чтобы ответить на ваши вопросы:
Почему разработчики JDK не обновили существующие методы в классе Option?
Концептуально, что будет идти против того, для чего следует использовать Optional
. Но, как отмечали другие, это было бы несовместимым с обратным изменением, поскольку вызовы orElse(null)
внезапно выдавали бы исключения.
Почему они не внедрили новый метод (который будет выброшен NPE, если второй аргумент равен null) в Необязательный класс?
API-интерфейсы расширяются только при значительном улучшении существующего кода. Я этого не вижу. Во многих случаях orElse
получает аргумент, который вызывающий создает специально как альтернативу для пустых опций - редко требуется сделать дополнительную проверку, чтобы проверить ее не 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);
и рассмотрим использование статического импорта, чтобы сделать его более читаемым.
Ответ 2
Почему разработчики JDK не обновили существующие методы в классе Option?
Потому что это приведет к нарушению изменения, которое нарушит многие существующие программы, а также потому, что метод должен позволить получать нуль, если это необходимо.
Почему они не внедрили новый метод (который будет выброшен NPE, если второй аргумент равен null) в Необязательный класс?
Возможно, потому, что это сделает API более запутанным и раздутым без каких-либо существенных преимуществ. Вы можете повернуть результат с помощью requireNonNull, если вы хотите, чтобы ваш код не возвращал null неожиданно.
Что следует использовать теперь Необязательно или Объекты?
Если вам нужно извлечь значение из необязательного объекта, возвращаемого методом, используйте опциональный метод. Если вы хотите, чтобы предпосылки были соблюдены для аргумента метода, который не должен иметь значение null, используйте Object.requireXxx. Дизайнеры JDK никогда не выступали за использование опциона только для того, чтобы обернуть значение и проверить значение null. Необязательно для возвращаемых значений.
Делают ли новые методы более предпочтительными объекты, чем Необязательно, поскольку они сразу же бросают NPE, а не позже в код, например, с помощью опции?
См. предыдущие пункты: вы не используете эти методы для выполнения одной и той же вещи.
Ответ 3
Дело в том, что эти две сигнатуры метода четко разные:
public static <T> T requireNonNullElse(T obj, T defaultObj)
против.
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
javadoc для второго метода читает:
Возвращает первый аргумент, если он не является нулевым и в противном случае возвращает ненулевое значение поставщика .get().
Другими словами: он использует поставщик, который вы здесь указываете.
Итак, ответ: вы используете вторую версию для ситуаций, когда вы хотите работать с поставщиком; и в противном случае вы просто берете "более простую" версию этого метода, которая принимает "менее сложный" параметр.
Обоснование этого: когда вы решаете между двумя вариантами, вы предпочитаете использовать тот, который проще/ "менее читатель удивителен". Другими словами: почему вы хотите предоставить поставщика, когда вы можете обойтись.
Что касается использования опций - имейте в виду, что их цель main должна была использоваться для возвращаемых типов; а не как параметры метода (см. здесь для дальнейшего чтения).
Затем: обновление существующих методов в классе, поставляемом "в поле", почти всегда не работает. Вы абсолютно не хотите изменить семантику того, что уже открыто и используется вашими клиентами; предполагая определенную семантику.
Ответ 4
Q. Почему разработчики JDK не обновили существующие методы в классе "Дополнительно"?
а. Потому что класс Optional
был разработан, чтобы избежать NPE.
Q. Почему они не внедрили новый метод (который вызовет NPE, если второй аргумент равен null) в Необязательный класс?
а. Тот же ответ.
Q. Что мы должны использовать теперь Необязательно или Объекты?.
а. И то и другое. Objects
для простых проверок "не нуль" и Optional
для цепных операций, таких как map
, flatMap
, `filter '.
Q. Новые методы делают объекты более предпочтительными, чем Необязательные, поскольку они сразу бросают NPE, а не позже, где-то в коде, например, с опцией?
а. Зависит от ситуации. Если у вас уже есть необязательное значение как возвращаемое значение некоторого метода, предпочтительнее использовать опцию.
Ответ 5
Итак, главное, если вам нравится использовать ifs для проверки нулевого или нет. Если у вас есть метод, который может принимать аргументы, которые могут иметь нулевое значение, было бы разумнее использовать объекты. Единственное разумное место для использования Необязательно - проверить вызов метода, который возвращает необязательный результат.
Разработчики хотели использовать более функциональный способ проверки нулевых значений, поэтому для этой цели используется конструктор Optional.ofNullable
, что не было хорошей практикой, поскольку оно создавало мусор.