正确使用Optional.ifPresent()

ray*_*man 78 java lambda optional java-8

我试图理解Java 8中API 的ifPresent()方法Optional.

我有简单的逻辑:

Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));
Run Code Online (Sandbox Code Playgroud)

但这会导致编译错误:

ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)
Run Code Online (Sandbox Code Playgroud)

我当然可以这样做:

if(user.isPresent())
{
  doSomethingWithUser(user.get());
}
Run Code Online (Sandbox Code Playgroud)

但这就像一张杂乱无章的null支票.

如果我将代码更改为:

 user.ifPresent(new Consumer<User>() {
            @Override public void accept(User user) {
                doSomethingWithUser(user.get());
            }
        });
Run Code Online (Sandbox Code Playgroud)

代码变得越来越脏,这让我想到回到旧的null支票.

有任何想法吗?

JB *_*zet 122

Optional<User>.ifPresent()采取一个Consumer<? super User>论点.你传递的是一个类型为void的表达式.所以这不编译.

Consumer旨在实现为lambda表达式:

Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));
Run Code Online (Sandbox Code Playgroud)

甚至更简单,使用方法参考:

Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);
Run Code Online (Sandbox Code Playgroud)

这与基本相同

Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
    @Override
    public void accept(User theUser) {
        doSomethingWithUser(theUser);
    }
});
Run Code Online (Sandbox Code Playgroud)

这个想法是doSomethingWithUser()只有在用户在场时才会执行方法调用.您的代码直接执行方法调用,并尝试将其void结果传递给ifPresent().

  • @rayman如果你有一个返回`Optional <User>`的函数,通常不需要将它存储在局部变量中.只需链接方法调用:`funcThatMightReturnUser().ifPresent(this :: doSomethingWithUser);` (8认同)
  • 哪个代码?您应该使用的一个是第二个,它调用实例(即非静态)方法doSomethingWithUser()。我看不到它如何混乱。那里的最后一个代码向您解释了lambda之前的世界中的lambda。不要使用它。 (4认同)
  • 该代码变得混乱..空检查将更加干净。您不是特别认为doSomethingWithUser不是静态方法吗? (2认同)
  • 是的,但是您可能习惯于使用匿名类,因此可以通过看到等效的匿名类来了解lambda的功能。这才是重点。 (2认同)

cst*_*992 12

除了@ JBNizet的答案之外,我对ifPresent的一般用例是组合ifPresent.isPresent():

旧方式:

Optional opt = getIntOptional();
if(opt.isPresent()) {
    Integer value = opt.get();
    // do something with value
}
Run Code Online (Sandbox Code Playgroud)

新方法:

Optional opt = getIntOptional();
opt.ifPresent(value -> {
    // do something with value
})
Run Code Online (Sandbox Code Playgroud)

对我来说,这更直观.

  • 但如果存在的话,里面的任何东西都应该返回 void,因为从里面返回的任何东西都会丢失 (3认同)
  • @valik 是的,就是这样。您不应该期望从那里返回一个值;它更像是“做这个”。 (3认同)

sch*_*ebe 7

为什么要编写简单的复杂代码?

确实,如果您绝对要使用Optional该类,那么最简单的代码就是您已经编写的代码...

if (user.isPresent())
{
    doSomethingWithUser(user.get());
}
Run Code Online (Sandbox Code Playgroud)

该代码的优点是

  1. 可读的
  2. 易于调试(断点)
  3. 不棘手

仅仅因为Oracle Optional在Java 8中添加了该类并不意味着该类必须在所有情况下都使用。

  • 使用 ifPresent 的主要好处是它消除了您手动调用 get() 的需要。手动调用 get() 很容易出错,因为很容易忘记先检查 isPresent,但如果使用 ifPresent 就不可能忘记 (2认同)
  • 好的,每次您使用“用户”对象时,您都应该调用 .ifPresent()。代码很快就会变得不可读,因为你会花太多时间阅读 .ifPresent() ! (2认同)

Tar*_*nyk 6

使用flatMap。如果存在值,则flatMap返回仅包含该值的顺序Stream,否则返回空Stream。所以没有必要使用ifPresent()。例:

list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

  • 可选:: stream需要java9 (2认同)
  • 这段代码 a) 比仅仅使用 if(opt.isPresent()) { val = opt.get());} 更长,b) 晦涩难懂,需要注释来向下一个开发人员解释您想要实现的目标c) 不能在 Java 8 中编译。 (2认同)

Ale*_*tin 5

您可以使用如下方法引用:

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);
Run Code Online (Sandbox Code Playgroud)

方法ifPresent()获取Consumer对象作为参数和(从 JavaDoc):“如果存在值,则使用该值调用指定的使用者。” 值是您的变量user

或者,如果此方法doSomethingWithUserUser类中,而不是static,则可以使用如下方法引用:

user.ifPresent(this::doSomethingWithUser);
Run Code Online (Sandbox Code Playgroud)

  • @AleksandrPodkutin你不应该仅仅为了运行一个方法而创建该类的新实例,在OP中听起来该方法与被调用的方法在同一类中,因此他应该使用`user.ifPresent(this ::: doSomethingWithUser);` (6认同)