【问题标题】:Is using Optional.ofNullable as a replacement for the ternary operator a good practice?使用 Optional.ofNullable 作为三元运算符的替代品是一种好习惯吗?
【发布时间】:2018-11-27 16:57:25
【问题描述】:

考虑这个表达式的用法:

String hi = Optional.ofNullable(sayHi()).orElse("-");

这实际上对应于这个三元表达式:

String hi = sayHi() != null ? sayHi() : "-";

在方法调用中使用Optional.ofNullable 是一种好习惯吗?或者只是额外的冗长编码?


我认识到Optional.ofNullable 实际上创建了一个变量并避免了两次调用sayHi() 方法。为了避免这个问题,你实际上可以创建一个额外的变量,但这增加了三元选项的冗长:

String hi = sayHi();
hi = hi != null ? hi : "-";

另一方面,Optional.ofNullablehi 不是null 的情况下创建一个额外的Optional 对象。所以肯定会有更多的开销。

所以使用这种类型的构造来代替三元构造似乎有一些优点和缺点。


顺便说一句:这是Optional.ofNullable的Java 8实现:

public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}

【问题讨论】:

    标签: java java-8 optional nullable


    【解决方案1】:

    在 JDK 9 或更高版本中,使用这个:

    String hi = Objects.requireNonNullElse(sayHi(), "-");
    

    这避免了在使用三元运算符时必须重复sayHi(),或者将其值分配给在三元中重用的局部变量。这可能是一个小小的改进。它还回避了是否使用Optional 的问题。 :-)

    【讨论】:

      【解决方案2】:

      每当我想到将可选 API 用于特定目的时,我总是提醒自己它的目的是什么以及为什么将它引入 JDK,即

      可选,旨在为库方法提供有限的机制 返回明确需要表示“无结果”的类型,并且 使用 null 极有可能导致错误 - Stuart Marks

      Optional 主要关注可能有也可能没有返回值的返回类型。

      在您的这个特定示例中过度使用这种结构只会导致额外的内存分配和 GC 开销。

      我会保持简单,而是这样做:

      String hi = sayHi();
      if(hi == null) hi = “-“;
      ...
      

      【讨论】:

      • 猫王真的很方便。
      • @chrylis 同意,因为我是它的粉丝,但其他人认为将它集成到语言中并不重要......来自 C#,这归结为 String hi = sayHi() ?? “-”;这是 IMO 的一项改进。
      • 加一个引用我的话。 :-) 实际上,Brian Goetz 提出了最初的措辞,他和我一起编造了它。
      • @StuartMarks 确实很高兴,感谢您的纠正。
      【解决方案3】:

      在方法调用中使用Optional.ofNullable 是一种好习惯吗?

      Conceptually,这是一种不好的做法。基本思想是表示没有返回值,而不是包装可能是null 的所有内容。我强烈反对这种用法。

      或者只是额外的冗长编码?

      在我看来,这是一次让您的代码更时尚的失败尝试。 (“看,我们正在使用来自 Java 8 的全新 Optional!”)

      比起简洁,我更喜欢可读性和清晰性。

      Optinal 的这种用法不明确,但会引发问题:

      为什么要包装变量?
      你打算怎么处理这个Optional
      会在下面使用/归还吗?

      它也不简洁:你的第二行更短。

      为了避免这个问题,您实际上可以创建一个额外的变量,但这会增加三元选项的冗长性。

      您没有创建额外的变量。单行版本可能是:

      String hi = (hi = sayHi()) != null ? hi : "-";
      

      不过,你的两行建议绝对没问题:

      String messageContent = sayHi();
      String hi = messageContent != null ? messageContent : "-";
      

      【讨论】:

        【解决方案4】:

        如果您要允许Optional 进入您的工作流程,那么您应该考虑修改sayHi() 方法,使其返回Optional&lt;String&gt;,这将使结果更加优雅:

        hi = sayHi().orElse("-");
        

        如果您不想将Optional 引入您的工作流程(因为它确实创建了一个包含可选值的附加对象),那么您最好坚持使用简单的空检查和三元运算符。

        关于Optional 的性能成本(例如增加垃圾收集),您需要分析您的应用程序并确定这是否是一个真正的问题。

        此外,如果您对String 最感兴趣,请注意Objects.toString(Object, String) 方法,如果对象为空,则该方法返回默认值:

        hi = Objects.toString(hi, "-");
        

        这比手动编写代码更整洁、更优雅。

        【讨论】:

        • 感谢Objects.toString的建议。对于字符串来说,这似乎确实要好得多。我无法控制在另一个笔记上调用的方法,所以我不能返回 Optional
        【解决方案5】:

        我认为这主要是个人品味的问题。

        在我看来,只返回一个Optional&lt;String&gt; 并让调用者处理缺失值会更有意义。

        可选,作为一元类型,除了获取 alt 值之外,还可以利用更多。

        另一方面,您的 运算符 似乎足够简洁,如果始终使用它可能会很实用。

        我不认为性能是一个大问题。

        【讨论】:

          【解决方案6】:

          简而言之:避免使用Optional 类型。 Optional 在返回类型上的主要论点是,“客户很容易忘记处理空返回值的可能性。Optional 丑陋而且在你的脸上,所以客户不太可能忘记处理空返回值的可能性。在其他任何地方,程序员都应该继续使用普通引用,这可能是空的。

          我写了一篇关于使用 Java 的 Optional 类型的优缺点的讨论:Nothing is better than the Optional type

          【讨论】:

            猜你喜欢
            • 2012-01-03
            • 2010-10-16
            • 2012-05-30
            • 1970-01-01
            • 1970-01-01
            • 2020-08-19
            • 2011-03-06
            • 2013-06-15
            • 1970-01-01
            相关资源
            最近更新 更多