如何使用 Java Optional 优雅地替换三元运算符
Posted
技术标签:
【中文标题】如何使用 Java Optional 优雅地替换三元运算符【英文标题】:How to use Java Optional to elegantly replace Ternary operators 【发布时间】: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()
【参考方案1】:
为避免急切地评估 else 分支,请使用 orElseGet
,它采用函数接口 Supplier
的实例:
return recordA.map(
record -> record.getCreatedAt())
.orElseGet(() -> recordB.get().getCreatedAt());
【讨论】:
如果recordA
和recordB
属于同一类型,可以简写为recordA.orElseGet(recordB::get).getCreatedAt()
@Andreas 在recordB
为空Optional
时不起作用。
@tsolakp 它与问题和这个答案完全相同,即如果recordA
和recordB
都是空的,所有3 个都会抛出异常。
@Andreas。如果recordA
和recordB
为空,则不确定OP 是否想要异常。
@tsolakp 但是你为什么要解决我的评论,好像我评论的代码是唯一有问题的代码?也解决答案,因为它有同样的问题。更好的是,对问题写评论,通知 OP 潜在问题,并询问它是否是一个问题。也许逻辑是它们中至少有一个是非空的,这使它成为非问题。这当然不是我建议的较短代码引入的问题,就像我写 orElse(recordB.get())
时那样,但这不是我写的。【参考方案2】:
我关于recordB
是Optional
的问题没有得到解答,但如果它是Optional
,那么你不能安全地调用它的get
方法,你需要检查它是否为空。如果recordA
和recordB
都为空Otional
s,则此处安全调用以获取记录或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 *** answer。
recordA.ifPresentOrElse(
value -> recordA.get().getCreatedAt(),
() -> recordB.get().getCreatedAt()
);
【讨论】:
以上是关于如何使用 Java Optional 优雅地替换三元运算符的主要内容,如果未能解决你的问题,请参考以下文章