可选的isPresent与orElse(null)

时间:2018-08-27 21:55:15

标签: java java-8 spring-data-jpa

我正在项目中更新对Spring 5的依赖关系,并遭到编译错误的轰炸,其中findOne()的方法定义已由findById()替换,现在返回了Optional(正确如果我错了我。

在重构的过程中,我遇到了多种可以选择采用的方法,因此,我希望有一些输入是首选的。

第一种方法:

ExpectedPackage ep = expectedPackageRepository.findById(1).orElse(null);
if(ep != null){
    ep.setDateModified(new Date());
    expectedPackageRepository.saveAndFlush(ep);
}

第二种方法:

Optional<ExpectedPackage> ep = expectedPackageRepository.findById(1);
if(ep.isPresent()){
    ep.get().setDateModified(new Date());
    expectedPackageRepository.saveAndFlush(ep.get());
}

还是我错过了第三种更好的方法?我经历了几个问题和几篇文章,但没有找到明确的答案。

4 个答案:

答案 0 :(得分:19)

您也可以这样做:

expectedPackageRepository.findById(1).ifPresent(
    ep -> {
        ep.setDateModified(new Date());
        expectedPackageRepository.saveAndFlush(ep);
    }
);

理想情况下,您还可以将方括号({})之间的部分提取为单独的方法。然后,您可以这样写:

    expectedPackageRepository.findById(1).ifPresent(this::doSomethingWithEp);

位置:

void doSomethingWithEp(ExpectedPackage ep) {
    ep.setDateModified(new Date());
    expectedPackageRepository.saveAndFlush(ep);
}

您可以在此处阅读ifPresent的文档:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-

如状态所示,如果存在该值,它将执行指定的操作,否则不执行任何操作。

答案 1 :(得分:6)

另一个答案基本上是对第二种方法的某种重构,本质上没有错,这只是样式问题。当然,链接和提取到一个单独的方法将使它更易读和清楚(毫无疑问(我是+1)),尤其是因为正确使用了ifPresent

我只是在这里补充说,get被认为是某种设计错误(或者可能是错误的方法名称,可能来自guava思维定势)。即使在get被记录为在缺少该值时抛出异常的情况下,使用它也是有点怪异的(如果您认为这里的吸气剂,您不会指望getter会抛出异常)。而且,您不会期望get之后 isPresent之后被调用,至少在与Optional的最初交互中不需要。因此,建议get被弃用(并希望删除),因此java-10添加了一个更好的添加项orElseThrow()-在您读完之后就很有意义了,因为抛出部分是以方法,所以没有惊喜。

另外,有人应该告诉您new Date()的用法,当它与java-8中的Optional一起使用时看起来很奇怪,已经有更好的与时间/日期相关的类了。

我也不太确定为什么在有PreUpdate/PrePersist之类的春季注释时,为什么要手动更新修改日期。

答案 2 :(得分:5)

是的,还有其他方法。

如果您绝对希望始终有一个值,那么如果出现空值,则使用Optional::orElseThrow引发异常。

如果您期望null可能到达,并且可以使用备用实例作为后备选项,请使用Optional::orElse

如果没有备用实例,但是您可以调用一个函数来提供备用实例,请使用Optional::orElseGet

如果您不希望收到空值,并且不想在空值到达时采取任何措施,请使用Optional::ifPresent。如果值到达,则传递要运行的代码块。

如果您只关心到达的值是否满足某些要求,请使用Optional::filter。通过Predicate定义您的要求。例如,我们仅关心Optional< String >包含文本其中文本中包含单词purple的情况:myOptional.filter( s -> s.contains( "purple" ) ).ifPresent( this::print ) ;。如果收到null,则永远不会发生我们所需的操作(在此示例中为print的调用)。如果接收到一个值但不满足我们的谓词,则我们期望的操作将永远不会发生。


执行if( myOptional.isPresent() ) { SomeClass x = myOptional.get() ; … }是有效且安全的。但这不是Optional的初衷,因为它与进行老式的空检查if ( null == x ) { … }基本相同。 Optional上的其他方法提供了一种更清晰,更优雅的方式来表达您对可能到达null的意图。

答案 3 :(得分:1)

您也可以这样做:

Optional<ExpectedPackage> updatedPackage = expectedPackageRepository.findById(1).map(ep -> {
    ep.setDateModified(new Date());
    return expectedPackageRepository.saveAndFlush(ep);
});