151

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?

5 Answers 5

228

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

8
  • 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
    Commented Jun 15, 2014 at 9: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
    Commented Jun 15, 2014 at 10:01
  • 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
    Commented Jun 15, 2014 at 10:21
  • 1
    You have nothing to modify. Leave it as it is, and use the second example: user.ifPresent(this::doSomethingWithUser);
    – JB Nizet
    Commented Jun 15, 2014 at 15:36
  • 12
    @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::doSomethingWithUser); Commented Jun 15, 2014 at 17:45
50

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.

4
  • 3
    but whatever is inside ifpresent should be return void, because anything u return from inside is lost
    – valik
    Commented Apr 15, 2021 at 18:59
  • 3
    @valik Yes, that is so. You shouldn't expect to return a value from there; it's more like "do this".
    – cst1992
    Commented Apr 16, 2021 at 5:20
  • 2
    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 Commented May 14, 2022 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 Commented Jan 18, 2023 at 8:58
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.

3
  • 7
    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 Commented Dec 2, 2019 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
    Commented Dec 2, 2019 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 Commented May 14, 2022 at 22:18
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);
4
  • 1
    But doSomethingWithUser is not a static method nor it's class.
    – rayman
    Commented Jun 15, 2014 at 9:57
  • 1
    @rayman Ok, if not static you can do like this: user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser); Commented Jun 15, 2014 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
    Commented Jan 28, 2018 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. Commented Jul 8, 2019 at 15:06
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());
2
  • 5
    Optional::stream needs java9
    – avmohan
    Commented Jul 3, 2018 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. Commented Jun 8, 2022 at 19:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.