Proper usage of Optional.ifPresent()

2019-02-02 02:23发布

问题:

I am trying to understand the ifPresent() method of the Optional API in Java 8.

I have simple logic:

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

But this results in a compilation error:

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

Of course I can do something like this:

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

But this is exactly like a cluttered null check.

If I change the code into this:

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

The code is getting dirtier, which makes me think of going back to the old null check.

Any ideas?

回答1:

Optional<User>.ifPresent() takes a Consumer<? super User> as argument. You're passing it an expression whose type is void. So that doesn't compile.

A Consumer is intended to be implemented as a lambda expression:

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

Or even simpler, using a method reference:

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

This is basically the same thing as

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

The idea is that the doSomethingWithUser() method call will only be executed if the user is present. Your code executes the method call directly, and tries to pass its voir result to ifPresent().



回答2:

In addition to @JBNizet's answer, my general use case for ifPresent is to combine .isPresent() and .get():

Old way:

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

New way:

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

This, to me, is more intuitive.



回答3:

Use flatMap. If a value is present, flatMap returns a sequential Stream containing only that value, otherwise returns an empty Stream. So there is no need to use ifPresent() . Example:

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


回答4:

You need to use it like this:

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

Method ifPresent() get Consumer object as a paremeter and (from JavaDoc): "If a value is present, invoke the specified consumer with the value." Value its your variable user.



回答5:

Why making simple when you can write some complicated code !

Indeed, if you will absolutely use Optional class, the simple code is what you have already written ...

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

This code has the advantages to be

  1. readable
  2. easy to breakpoint
  3. not tricky

It is not because Oracle has added Optional class in Java 8 that this class must me used in all situation.