【问题标题】:java.util.Objects vs Optional which is preferable?java.util.Objects 与 Optional 哪个更可取?
【发布时间】:2017-07-17 20:44:30
【问题描述】:

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

Objects#requireNonNullElse

分别

Objects#requireNonNullElseGet()Java-9

如果第一个参数不为空,则两者都将返回,否则返回非空的第二个参数或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

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 如果第二个参数为空)到可选类?
  • 我们现在应该使用什么 Optional 或 Objects?
  • 新方法是否使 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);

【问题讨论】:

    标签: java optional java-9


    【解决方案1】:

    您的问题“哪个更可取?”的最短答案一直是开发者最喜欢的“它取决于”?,因为 Objects::requireNonNullElseOptional 涵盖不同的用例。

    两种选择

    在回答您的问题之前,我想介绍一下这两种选择的背景。

    Objects::requireNonNullElse

    Objects::requireNonNull 确保调用的结果永远不会为空(因此得名)。它通常用于简洁地验证构造函数或方法的参数,让读者一眼就能验证被赋值返回值的变量不能为空。

    所以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。这是真的,我认为它已被考虑,但如果这三种情况之一可能实际上允许调用的最终结果为null,即使名称显示 required non nullrequireNonNull... API 将非常奇怪/em>。

    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-checks 的替代品。从这个意义上说,orElseorElseGet 是从Optional 回到可空类型世界的后门,有时null 正是你想要使用的东西,如果某些东西不存在,所以他们接受@ 是有意义的987654347@ 作为参数(或供应商的结果)。

    您的问题

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

    为什么 JDK 开发者没有更新 Optional 类中已有的方法?

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

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

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

    我们现在应该使用什么 Optional 或 Objects?

    如果您有一个变量(无论是本地变量、参数还是字段)并且您想确保它不为空,请使用Objects。如果您想返回一些可能为空的内容,请考虑将其包装在 Optional 中。对创建Optional(而不是获取一个调用形式)并在同一链末尾解包的代码持怀疑态度。

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

    我确信现在很清楚,它们涵盖了不同的用例。但是让我解决“而不是稍后在代码中的某个地方,例如使用 Optional”:无论您做什么,请确保在您的代码中检查您想要的可空性属性(可以是 null 或不是)。不要返回您认为不能是 null 的东西,但事实证明这是因为您没有检查。如果发生这种情况,那不是Optional 的错。

    如果我有旧代码,例如:

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

    绝对是Objects.requireNonNullOrElse(str,"other string");,并考虑使用静态导入使其更具可读性。

    【讨论】:

    • 我猜我用错了Optional。我在想我可以用它们作为if-null-check 的替代品。现在我将回顾我的方法。非常感谢。
    • 这就是 SO 的用途。 :) 如果您的问题得到充分解决,请记住接受其中一个答案。
    【解决方案2】:

    JDK 开发者为什么没有更新 Optional 类中已有的方法?

    因为这会引入会破坏许多现有程序的重大更改,并且该方法应允许在需要时获取 null。

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

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

    我们现在应该使用什么 Optional 或 Objects?

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

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

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

    【讨论】:

      【解决方案3】:

      重点是:这两个方法签名明显不同:

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

      对比

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

      第二种方法的javadoc如下:

      如果第一个参数不为空,则返回第一个参数,否则返回supplier.get()的非空值。

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

      因此,答案是:您在希望与供应商合作的情况下使用第二个版本;否则,您只需采用采用“不太复杂”参数的该方法的“更简单”版本。

      其背后的原因:当您在两个选项之间做出选择时,您更喜欢使用更容易/“读者不那么惊讶”的那个。换句话说:你为什么要提供供应商,什么时候可以不提供。

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

      然后:更新类中的现有方法交付“到现场”几乎总是不行。您绝对想要更改已经公开并被客户使用的东西的语义;假设特定的语义。

      【讨论】:

      • 是的,但Optinal#orElseGetObjects.requireNotNullElseGet 都接受供应商。如果 supplier.get() 返回 null,第二个将抛出 NPE 的唯一区别。
      • 这方面在最后一段中有所涉及——给我们Java的人认为使用Optional作为方法参数不是一个好习惯;那么他们为什么要提出一个正式的方法签名呢?!
      • 我在考虑以下情况。假设方法内部有一个检查:String str = null; String result = str == null ? "other string" : str; 它不是方法参数。只是一张支票。现在我想用最新的语言特性重构它。记住ObjectsOptional 之间的区别。 result = Optional.ofNullable(str).orElse("other string");result = Objects.requireNonNullOrElse(str,"other string); 哪个更可取?
      【解决方案4】:

      问。为什么JDK开发者没有更新Optional类中已有的方法?

      A.因为Optional 类旨在避免 NPE。

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

      A.同样的答案。

      问。我们现在应该使用 Optional 还是 Objects?。

      A.两个都。 Objects 用于简单的“非空”检查,Optional 用于链操作,如mapflatMap、`filter'。

      问。新方法是否使 Objects 比 Optional 更可取,因为它们会立即抛出 NPE,而不是像 Optional 那样稍后在代码中的某个地方抛出?

      A.视情况而定。如果您已经将 Optional 作为某个方法的返回值,那么最好使用 Optional。

      【讨论】:

        【解决方案5】:

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

        开发人员希望使用更实用的方法来检查空值,因此在 where 使用构造 Optional.ofNullable 来达到此目的,这不是一个好的做法,因为它会产生垃圾。

        【讨论】:

          猜你喜欢
          • 2011-01-28
          • 1970-01-01
          • 2017-11-26
          • 2012-07-15
          • 2020-06-16
          • 2016-10-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多