java.util.Objects vs可选哪个更好?

时间:2017-02-27 09:42:36

标签: java optional java-9

java.util.Objects类扩展了许多新方法

Objects#requireNonNullElse

分别

Java-9中的

Objects#requireNonNullElseGet()

如果第一个参数为非null,则返回第一个参数,否则返回非null的第二个参数或者supplier.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"

但新功能与OptionalOptional#orElseOptional#orElseGet

中已存在的功能重叠
jshell> Optional.ofNullable(nullStr).orElse("lorem ipsum");
$17 ==> "lorem ipsum"

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

Objects中的新方法与相应的Optional方法之间的唯一区别是供应商的第二个参数或值必须为非空,否则Objects抛出NPE:< / p>

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开发人员没有更新Optional中的现有方法 类?
  • 为什么他们没有引入一种新的方法(它会抛出 NPE,如果第二个参数为null)为Optional class?
  • 我们现在应该使用Optional或Objects?
  • 新方法使对象比Optional更可取 将立即抛出NPE而不是稍后在代码中的某处 喜欢使用Optional?

如果我有遗留代码,例如:

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

这只是方法内部的简单检查。我想使用最新的语言功能重新考虑它。现在考虑Optional.orElseObjects.requireNonNullOrElse之间的差异哪个更好?

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

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

5 个答案:

答案 0 :(得分:18)

您问题的最短答案&#34;哪个更好?&#34;是开发人员最喜欢的&#34;它取决于&#34;因为Objects::requireNonNullElseOptional涵盖了不同的用例。

两种选择

在回答你的问题之前,我想先介绍两种选择。

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...,那么null API将非常奇怪,即使名称说要求非空

Optional

Optional was designed作为返回参数,如果返回null很可能导致NPE(例如Stream的终端操作,其中它是第一次使用)。虽然有些开发人员更喜欢在更多情况下使用它(比较Stephen Colebourne's pragmatic approachmy strict approach),但没有人真的建议在演示中使用它:

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

Optional是一种在类型系统中表达某些内容可能会丢失的方法 - 它不能替代if - null - 检查。从这个意义上来说,orElseorElseGet是从Optional后门进入可空类型世界的后门,有时null就是你想要使用的东西null不存在,所以他们接受Optional作为论据(或供应商的结果)是有道理的。

您的问题

现在我们有了解答问题所需的内容:

  

为什么JDK开发人员没有更新Optional类中的现有方法?

从概念上讲,这将违背orElse(null)应该使用的内容。但是,正如其他人所提到的,这将是一个向后不兼容的变化,因为对orElse的调用会突然抛出异常。

  

为什么他们没有引入一个新方法(如果第二个参数为null则将NPE抛出)到Optional类?

只有在可以预期对现有代码进行大量改进时才会扩展API。我在这里看不到。在许多情况下,null会得到一个参数,调用者专门为空选项创建一个替代方案 - 很少需要进行额外检查以验证它不是orElse(requireNonNull(x))。如果您真的需要,请致电Objects

  

我们现在应该使用什么可选或对象?

如果您有变量(无论是本地变量,参数还是字段),并且您想确保它不为空,请使用Optional。如果你想返回一些可能为null的东西,可以考虑将它包装在Optional中。怀疑创建null的代码(而不是通过调用形成一个代码)并在同一个链的末尾展开它。

  

新方法是否使对象比Optional更可取,因为它们会立即抛出NPE,而不是稍后在代码中的某个地方抛出,比如可选?

我现在很清楚,它们涵盖了不同的用例。但是,让我解决&#34;而不是稍后在代码中的某个地方,例如使用Optional&#34;:无论你做什么,请确保在你的代码中检查你想要的nullablity属性(可以是null)。不要归还你认为不能Optional的东西,但结果却是因为你没有检查。如果发生这种情况,那就不是String str = null; String result = str == null ? "other string" : str; 的错误。

  

如果我有遗留代码,例如:

Objects.requireNonNullOrElse(str,"other string);

绝对{{1}}并考虑使用静态导入使其更具可读性。

答案 1 :(得分:4)

  

为什么JDK开发人员没有更新Optional类中的现有方法?

因为这会引入一个突破性的变化,会破坏许多现有的程序,并且因为该方法应该允许在需要时变为空。

  

为什么他们没有引入一个新方法(如果第二个参数为null将抛出NPE)到Optional类?

可能是因为这会使API更加复杂和臃肿,没有明显的优势。如果要确保代码不会意外返回null,仍然可以使用requireNonNull包装结果。

  

我们现在应该使用什么可选或对象?

如果需要从方法返回的可选项中提取值,请使用Optional的方法。如果要确保对于不应为null的方法的参数,请遵守前提条件,请使用Object.requireXxx。 JDK设计者从未提倡使用Optional只是为了包装一个值并检查null。可选是返回值。

  

新方法是否使对象比Optional更可取,因为它们会立即抛出NPE,而不是稍后在代码中的某个地方抛出,比如可选?

请参阅前面的观点:您不要使用这些方法来做同样的事情。

答案 2 :(得分:3)

关键是:这两个方法签名明显不同:

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

VS

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

第二种方法的javadoc为:

如果它是非null,则返回第一个参数,否则返回supplier.get()的非null值。

换句话说:它使用您在此处提供的供应商

因此,答案是:在想要与供应商合作的情况下,您使用第二个版本;否则你只需要更简单的&#34;采用&#34;不那么复杂的方法的版本&#34;参数。

背后的理由:当你决定两个选项时,你更喜欢那个更容易/更少读者惊喜的#34;使用。换句话说:为什么你想在没有供应商的情况下提供供应商。

关于使用Optionals - 请注意,他们的主要目标将用于返回类型;不作为方法参数(参见here进一步阅读)。

然后:更新已交付的类中的现有方法&#34;到字段&#34;几乎总是不行。你绝对不会想要改变已经公开并被客户使用的东西的语义;假设具体的语义。

答案 3 :(得分:0)

  

Q值。为什么JDK开发人员没有更新Optional类中的现有方法?

一个。因为Optional类旨在避免NPE。

  

Q值。为什么他们没有引入一个新方法(如果第二个参数为null将抛出NPE)到Optional类?

一个。同样的答案。

  

Q值。我们现在应该使用Optional或Objects?。

一个。都。 Objects用于简单的“非空”检查,Optional用于链式操作,例如mapflatMap,“过滤器”。

  

Q值。新方法是否使对象比Optional更可取,因为它们会立即抛出NPE而不是稍后在代码中的某个地方抛出,比如可选吗?

一个。取决于情况。如果您已经将Optional作为某些方法的返回值,那么最好使用Optional。

答案 4 :(得分:0)

所以主要的一点是,如果你喜欢使用ifs检查是否为null。如果你有一个方法可以接受可以为null值的参数,那么使用Objects会更有意义。使用Optional的唯一合理位置是验证对返回可选结果的方法的调用。

开发人员希望使用更多功能性的方法来检查空值,因此使用构造Optional.ofNullable来实现此目的,这不是一个好习惯,因为它正在创建垃圾。