正确使用Optional.ifPresent()


94

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

我有简单的逻辑:

Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));

但这会导致编译错误:

ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)

我当然可以做这样的事情:

if(user.isPresent())
{
  doSomethingWithUser(user.get());
}

但是,这就像是一张混乱的null支票。

如果我将代码更改为此:

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

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

有任何想法吗?

Answers:


154

Optional<User>.ifPresent()需要Consumer<? super User>作为参数。您正在向其传递类型为void的表达式。因此,它不会编译。

使用者应被实现为lambda表达式:

Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));

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

Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);

这基本上与

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

想法是doSomethingWithUser()仅当用户在场时才执行方法调用。您的代码直接执行方法调用,并尝试将其无效结果传递给ifPresent()


2
该代码变得混乱..空检查将更加干净。您是不是特别认为doSomethingWithUser不是静态方法
rayman 2014年

4
哪个代码?您应该使用的一个是第二个,它调用实例(即非静态)方法doSomethingWithUser()。我看不到它如何混乱。最后的代码在那里向您解释了lambda之前的世界中的lambda。不要使用它。
JB Nizet 2014年

2
是的,但是您可能习惯于匿名类,因此通过查看等效的匿名类可以了解lambda的功能。这才是重点。
JB Nizet 2014年

1
您没有任何修改。保持原样,并使用第二个示例:user.ifPresent(this::doSomethingWithUser);
JB Nizet 2014年

10
@rayman如果您有返回的函数,Optional<User>则通常无需将其存储在局部变量中。只需链接方法调用即可:funcThatMightReturnUser().ifPresent(this::doSomethingWithUser);
Stuart Marks 2014年

19

除了@JBNizet的答案,我的一般用例ifPresent是将.isPresent()and 结合使用.get()

旧方法:

Optional opt = getIntOptional();
if(opt.isPresent()) {
    Integer value = opt.get();
    // do something with value
}

新方法:

Optional opt = getIntOptional();
opt.ifPresent(value -> {
    // do something with value
})

对我来说,这更直观。


7

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

list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());

3
可选:: stream需要java9
avmohan

7

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

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

if (user.isPresent())
{
    doSomethingWithUser(user.get());
}

该代码的优点是

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

甲骨文已经Optional在Java 8中添加了该类,并不意味着必须在所有情况下都使用该类。


1
使用ifPresent的主要好处是它消除了您手动调用get()的需要。调用get()手动容易出错,因为它很容易忘记先检查isPresent,但它不可能为你,如果你使用ifPresent忘记
dustinroepsch

1
好的,每次使用“ user”对象时,都应调用.ifPresent()。该代码将很快变得难以阅读,因为您会花太多时间阅读.ifPresent()!
schlebe

2
有关固定拼写错误您的个人资料页VB.NetNetbeans的SqlServer的PostgreSQL的MySQL的,和LINQ,你可以用我的服务也有。相应的单词表
彼得·莫特森

7

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

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

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

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

user.ifPresent(this::doSomethingWithUser);

1
但是doSomethingWithUser不是静态方法,也不是类。
rayman 2014年

@rayman好吧,如果不是静态的,您可以这样做:user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
Aleksandr Podkutin14年

7
@AleksandrPodkutin您不应该只为了运行一个方法而创建该类的新实例,在OP中,听起来该方法与所调用的方法位于同一类中,因此他应该使用user.ifPresent(this::doSomethingWithUser);
Marv

@Marv我没有看到与它在同一班级的任何确认书。但是,如果您有这种感觉,我同意他必须使用user.ifPresent(this::doSomethingWithUser);。我将其添加到我的答案中。
Aleksandr Podkutin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.