Proper usage of Optional.ifPresent()

276,219

Solution 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 void result to ifPresent().

Solution 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.

Solution 3

Why write complicated code when you could make it simple?

Indeed, if you are absolutely going to use the Optional class, the most simple code is what you have already written ...

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

This code has the advantages of being

  1. readable
  2. easy to debug (breakpoint)
  3. not tricky

Just because Oracle has added the Optional class in Java 8 doesn't mean that this class must be used in all situation.

Solution 4

You can use method reference 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 it is your variable user.

Or if this method doSomethingWithUser is in the User class and it is not static, you can use method reference like this:

user.ifPresent(this::doSomethingWithUser);

Solution 5

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());
Share:
276,219
rayman
Author by

rayman

Updated on July 09, 2020

Comments

  • rayman
    rayman almost 4 years

    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?

  • rayman
    rayman almost 10 years
    But doSomethingWithUser is not a static method nor it's class.
  • rayman
    rayman almost 10 years
    That code is getting cluttered.. a null check will be much more cleaner. don't you think?s specially that doSomethingWithUser is not a static method
  • JB Nizet
    JB Nizet almost 10 years
    Which code? The one you should use is the second one, which calls the instance (i.e. non-static) method doSomethingWithUser(). I don't see how it's cluttered. The last code is there to explain you the equivalent of the lambda in a pre-lambda world. Don't use it.
  • Aleksandr Podkutin
    Aleksandr Podkutin almost 10 years
    @rayman Ok, if not static you can do like this: user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
  • rayman
    rayman almost 10 years
    Ahh I understand you. If i am not in a lambda world there is not usage to use the Optional api eh
  • JB Nizet
    JB Nizet almost 10 years
    Yes, but you might be used to anonymous classes and thus understand what the lambda does by seeing an anonymous class equivalent. That's the point.
  • rayman
    rayman almost 10 years
    How would you modify the doSomethingWithUser to "enjoy" a fully completed best practice lambda's world?
  • JB Nizet
    JB Nizet almost 10 years
    You have nothing to modify. Leave it as it is, and use the second example: user.ifPresent(this::doSomethingWithUser);
  • Stuart Marks
    Stuart Marks almost 10 years
    @rayman If you have a function that returns Optional<User> there is often no need to store it in a local variable. Just chain the method calls: funcThatMightReturnUser().ifPresent(this::doSomethingWithUse‌​r);
  • Marv
    Marv over 6 years
    @AleksandrPodkutin you shouldn't create a new instance of the class just to run one method, from the OP it sounds like the method is in the same class as it's being called from, thus he should use user.ifPresent(this::doSomethingWithUser);
  • avmohan
    avmohan almost 6 years
    Optional::stream needs java9
  • Blake Neal
    Blake Neal almost 6 years
    I know this is resurrecting an old thread, but it's worth noting that a big benefit of using optionals is that null checks are no longer necessary, and if you stricken the contract by using Option.of() (instead of Optional.ofNullable()), this insert of a null will throw a NullPointerException (which is fail fast), and will not futilize polymorphism
  • Aleksandr Podkutin
    Aleksandr Podkutin almost 5 years
    @Marv I don't see any affirmation form OP that it's in the same class. But if you have such feelings, I agree that he have to use user.ifPresent(this::doSomethingWithUser);. I will add it to my answer.
  • dustinroepsch
    dustinroepsch over 4 years
    The major benefit of using ifPresent is that it removes the need for you to ever call get() manually. Calling get() manually is error prone, as it is easy to forget to check isPresent first, but it's impossible for you to forget if you use ifPresent
  • schlebe
    schlebe over 4 years
    Ok and each time you will use 'user' object you should to call .ifPresent(). The code will quickly become unreadable because you will read .ifPresent() too much time !
  • valik
    valik about 3 years
    but whatever is inside ifpresent should be return void, because anything u return from inside is lost
  • cst1992
    cst1992 about 3 years
    @valik Yes, that is so. You shouldn't expect to return a value from there; it's more like "do this".
  • Andrey M. Stepanov
    Andrey M. Stepanov almost 2 years
    This, to me, is more intuitive. - especially taking into consideration that here YOU CAN NOT assign that value to anything because that 'anything' must be final inside lambda. What a great advantage then
  • Andrey M. Stepanov
    Andrey M. Stepanov almost 2 years
    the major benefit of using ifPresent is not at all that - it just intended to operate with another argument, Consumer, which is not applicable in all cases