如何使用 Java Optional 优雅替换三元运算符

How to use Java Optional to elegantly replace Ternary operators

一个超级简单的问题:

这是我使用传统三元运算符 ?

的纯 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 功能替换传统的三元运算符。

为了避免急切地评估 else 分支,使用 orElseGet,它采用功能接口 Supplier:

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

您正在寻找 .orElseGet(() -> recordB.get().getCreatedAt());,原因可以在 post -->

中找到

有些人可能会觉得它有点主观,但就我个人而言,默认情况下,每次都使用 orElseGet() 而不是 orElse 更有意义,除非默认对象已经构建,因为这将防止许多意外问题(假设您没有阅读 orElse 和 orElseGet 文档之间的差异),就像您现在面临的问题一样。

阅读 Java Optional – orElse() vs orElseGet()

的更多内容

我关于 recordBOptional 的问题没有得到回答,但如果它是 Optional 那么你不能安全地调用它的 get 方法,你需要检查它是否是否为空。如果 recordArecordB 都为空 Otionals.

,这里安全调用获取记录或 null
        recordA
            .map(Record::getCreatedAt)
            .orElseGet( () -> recordB.map(Record::getCreatedAt).orElse(null) );

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

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