154

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

233

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

Sign up to request clarification or add additional context in comments.

8 Comments

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
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.
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.
You have nothing to modify. Leave it as it is, and use the second example: user.ifPresent(this::doSomethingWithUser);
@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);
|
51

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 Comments

but whatever is inside ifpresent should be return void, because anything u return from inside is lost
@valik Yes, that is so. You shouldn't expect to return a value from there; it's more like "do this".
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
@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
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 Comments

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
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 !
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
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 Comments

But doSomethingWithUser is not a static method nor it's class.
@rayman Ok, if not static you can do like this: user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
@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 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.
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 Comments

Optional::stream needs java9
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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.