Proper usage of Optional.ifPresent()
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
- readable
- easy to debug (breakpoint)
- 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());
rayman
Updated on July 09, 2020Comments
-
rayman almost 4 years
I am trying to understand the
ifPresent()
method of theOptional
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 almost 10 yearsBut doSomethingWithUser is not a static method nor it's class.
-
rayman almost 10 yearsThat 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 almost 10 yearsWhich 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 almost 10 years@rayman Ok, if not static you can do like this:
user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
-
rayman almost 10 yearsAhh I understand you. If i am not in a lambda world there is not usage to use the Optional api eh
-
JB Nizet almost 10 yearsYes, 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 almost 10 yearsHow would you modify the doSomethingWithUser to "enjoy" a fully completed best practice lambda's world?
-
JB Nizet almost 10 yearsYou have nothing to modify. Leave it as it is, and use the second example:
user.ifPresent(this::doSomethingWithUser);
-
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::doSomethingWithUser);
-
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 almost 6 yearsOptional::stream needs java9
-
Blake Neal almost 6 yearsI 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 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 over 4 yearsThe 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 over 4 yearsOk 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 about 3 yearsbut whatever is inside ifpresent should be return void, because anything u return from inside is lost
-
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 almost 2 yearsThis, 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 almost 2 yearsthe 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