145

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?

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
rayman
  • 20,786
  • 45
  • 148
  • 246

5 Answers5

221

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().

jwismar
  • 12,164
  • 3
  • 32
  • 44
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 3
    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 – rayman Jun 15 '14 at 09:59
  • 6
    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. – JB Nizet Jun 15 '14 at 10:01
  • Ahh I understand you. If i am not in a lambda world there is not usage to use the Optional api eh – rayman Jun 15 '14 at 10:03
  • 2
    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. – JB Nizet Jun 15 '14 at 10:21
  • How would you modify the doSomethingWithUser to "enjoy" a fully completed best practice lambda's world? – rayman Jun 15 '14 at 11:59
  • 1
    You have nothing to modify. Leave it as it is, and use the second example: `user.ifPresent(this::doSomethingWithUser);` – JB Nizet Jun 15 '14 at 15:36
  • 12
    @rayman If you have a function that returns `Optional` there is often no need to store it in a local variable. Just chain the method calls: `funcThatMightReturnUser().ifPresent(this::doSomethingWithUser);` – Stuart Marks Jun 15 '14 at 17:45
  • 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 – Blake Neal Jul 11 '18 at 18:30
45

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.

Dev Null
  • 4,731
  • 1
  • 30
  • 46
cst1992
  • 3,823
  • 1
  • 29
  • 40
  • 3
    but whatever is inside ifpresent should be return void, because anything u return from inside is lost – valik Apr 15 '21 at 18:59
  • 2
    @valik Yes, that is so. You shouldn't expect to return a value from there; it's more like "do this". – cst1992 Apr 16 '21 at 05:20
  • 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 May 14 '22 at 22:16
  • @valik If you want to return a single value, `map` is the function of your choice, instead of `ifPresent`. But I agree, if you want to modify several veriables, it likely becomes complex – Daniel Alder Jan 18 '23 at 08:58
15

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);
Aleksandr Podkutin
  • 2,532
  • 1
  • 20
  • 31
  • 1
    But doSomethingWithUser is not a static method nor it's class. – rayman Jun 15 '14 at 09:57
  • 1
    @rayman Ok, if not static you can do like this: `user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);` – Aleksandr Podkutin Jun 15 '14 at 10:02
  • 9
    @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);` – Marv Jan 28 '18 at 19:12
  • @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. – Aleksandr Podkutin Jul 08 '19 at 15:06
15

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.

Brod
  • 1,377
  • 12
  • 14
schlebe
  • 3,387
  • 5
  • 37
  • 50
  • 6
    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 – dustinroepsch Dec 02 '19 at 21:47
  • 3
    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 ! – schlebe Dec 02 '19 at 22:34
  • 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 – Andrey M. Stepanov May 14 '22 at 22:18
6

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());
Taras Melnyk
  • 3,057
  • 3
  • 38
  • 34
  • 5
    Optional::stream needs java9 – avmohan Jul 03 '18 at 17:19
  • 2
    This code is a) longer than just using if(opt.isPresent()) { val = opt.get());} and b) obscure and in need of a comment to explain to the next developer what you are trying to achieve and c) does not compile in Java 8. – Breandán Dalton Jun 08 '22 at 19:37