Proper usage of Optional.ifPresent()
JavaLambdaJava 8OptionalJava Problem Overview
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?
Java Solutions
Solution 1 - Java
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 - Java
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 - Java
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 4 - Java
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 5 - Java
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());