【问题标题】:How to use Java Optional to elegantly replace Ternary operators如何使用 Java Optional 优雅地替换三元运算符
【发布时间】:2019-04-12 12:37:13
【问题描述】:

一个超级简单的问题:

这是我使用传统三元运算符 ? 的纯 Java 代码

public DateTime getCreatedAt() {
    return !recordA.isPresent() ? recordB.get().getCreatedAt() : recordA.get().getCreatedAt();
}

我最好的选择是:

public DateTime getCreatedAt() {
    return recordA.map(
        record -> record.getCreatedAt())
        .orElse(recordB.get().getCreatedAt());
  }

这可以编译,但看起来它的行为不正确。 它总是执行两个分支,例如当recordA isPresent() 时,它仍然执行recordB.get().getCreatedAt() 这抛出了我

java.util.NoSuchElementException: No value present

感谢任何帮助!

基本上,我想用更高级的 Optional/lamda 功能替换传统的三元运算符。

【问题讨论】:

  • .orElseGet(() -> recordB.get().getCreatedAt()); ?
  • 你需要orElseGet。您还可以使用两个选项和or()
  • recordB 也是可选的吗?
  • 看我的回答如果它是空的如何处理。
  • Optional 不应该以这种方式使用。我的意思是,如果你愿意,你可以像这样使用它,毕竟它是你的代码 :) 但我的意思是,它不是为了替换三元运算符或 if/else 语句而设计的。它的主要用途是作为一个返回类型,在 youtube Stuart Marks 的会议上讨论这个话题。您可以像这样改进您的实际代码:return (recordA.isPresent() ? recordA : recordB).get().getCreatedAt()

标签: java lambda java-8 optional conditional-operator


【解决方案1】:

为避免急切地评估 else 分支,请使用 orElseGet,它采用函数接口 Supplier 的实例:

return recordA.map(
    record -> record.getCreatedAt())
    .orElseGet(() -> recordB.get().getCreatedAt());

【讨论】:

  • 如果recordArecordB属于同一类型,可以简写为recordA.orElseGet(recordB::get).getCreatedAt()
  • @Andreas 在recordB 为空Optional 时不起作用。
  • @tsolakp 它与问题和这个答案完全相同,即如果recordArecordB 都是空的,所有3 个都会抛出异常。
  • @Andreas。如果recordArecordB 为空,则不确定OP 是否想要异常。
  • @tsolakp 但是你为什么要解决我的评论,好像我评论的代码是唯一有问题的代码?也解决答案,因为它有同样的问题。更好的是,对问题写评论,通知 OP 潜在问题,并询问它是否是一个问题。也许逻辑是它们中至少有一个是非空的,这使它成为非问题。这当然不是我建议的较短代码引入的问题,就像我写 orElse(recordB.get()) 时那样,但这不是我写的。
【解决方案2】:

我关于recordBOptional 的问题没有得到解答,但如果它是Optional,那么你不能安全地调用它的get 方法,你需要检查它是否为空。如果recordArecordB 都为空Otionals,则此处安全调用以获取记录或null。

        recordA
            .map(Record::getCreatedAt)
            .orElseGet( () -> recordB.map(Record::getCreatedAt).orElse(null) );

【讨论】:

  • 我在第二部分看不到Optional 的用途。创建一个Optional 只是为了调用orElse(null) 是一种已知的反模式。
  • 我同意。但是我们正在 OP 提供的示例中工作。理想情况下,getCreatedAt 也应该返回Optional,或者在我的回答中至少使用DateTime 的某种默认值而不是null
【解决方案3】:

您正在寻找.orElseGet(() -> recordB.get().getCreatedAt());,可以在这篇文章中找到原因 --> Difference between Optional.orElse() and Optional.orElseGet()

有些人可能会觉得它有点主观,但我个人认为,默认情况下,每次使用 orElseGet() 比使用 orElse 更有意义,除非默认对象已经构造为这将防止您现在面临的许多意外问题(假设您没有阅读 orElse 和 orElseGet doc 之间的区别)。

阅读更多来自Java Optional – orElse() vs orElseGet()

【讨论】:

    【解决方案4】:

    如果您使用的是 Java 9+,则可以使用 ifPresentOrElse() 方法 as more completely explained in this Stackoverflow answer

    recordA.ifPresentOrElse(
       value -> recordA.get().getCreatedAt(),
       () -> recordB.get().getCreatedAt()
    );
    

    【讨论】:

      猜你喜欢
      • 2021-07-03
      • 2010-12-03
      • 1970-01-01
      • 2015-01-09
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      相关资源
      最近更新 更多