Java Optional’s imperative checks, by usage of .isPresent()
and .get()
where a good gateway into using that container for avoiding Null Pointer Exceptions.
I like refactoring code and also dislike imperative checks for the Optional
type. So I decided to grab 4 examples from relatively old code that migrated to Java 8 and Optional
s.
There’s also the Guava’s Optional type, which offers more or less the same methods to work with
Optional
s.
The reason why I think using .isPresent()
is not as good, is because most of the times there’s no real advantage of using that method over != null
.
We can also avoid using If
syntax and making code less imperative and moving towards a more declarative approach.
Declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow.
I think Java Optional
s are a way to change how we think about Java imperative coding, together with Lambdas they can make the syntax terser.
Let’s get on with the examples. All these examples I extracted from code lying around in the different Java repositories at work; which I changed the names of variables, functions, et al., for reasons.
Example 1
private boolean isValidResource(final String resourceId, final boolean flag) {
final Optional<Resource> resourceOptional = serviceAClient.getResourceByID(resourceId, flag);
if (resourceOptional.isPresent()) {
final String propertyA = resourceOptional.get().getPropertyA();
return ("ValueA".equals(propertyA) || ("ValueB".equals(propertyA) && flag));
}
return false;
}
In this example, there a call to an external service to obtain a single resource, and from the Optional
resource, we need to access a property. If the resource or the property is not present, return false
;
We can enhance this example by the use of .map()
because accessing the property would be guarded by the optional
check on the property.
private boolean isValidResource(final String resourceId, final boolean flag) {
return serviceAClient.getResourceByID(resourceId, flag)
.map(resource -> resource.getPropertyA())
.map(propertyA -> ("ValueA".equals(propertyA) || ("ValueB".equals(propertyA) && flag)))
.orElse(false);
}
Example 2
public String getAccessToken() {
final Optional<String> accessTokenOptional = authService.getAccessToken();
return accessTokenOptional.isPresent() ? accessTokenOptional.get() : null;
}
In this second example, there’s no real advantage to using an optional over a simple != Null
check. We could avoid the ternary operator by using the method .orElse(null)
Which I think would make the code less verbose. Alternatively, we can add a second check to even guard against empty strings with a .filter()
that way we only return a string with a value or null.
public String getAccessToken() {
return authService.getAccessToken()
.filter(token -> StringUtils.hasText(token))
.orElse(null);
}
Example 3
public long getCurrentUserId() {
final Optional<Long> userIdOptional = new UserService().getUserId();
if (!userIdOptional.isPresent()) {
throw new NoCredentialsException("User id not found");
}
return userIdOptional.get();
}
This example, while seemingly trivial can be made in a more declarative style by using the .orElseThrow()
method from the Optional
resource.
This will effectively remove the If
statement, making the overall function more terse.
public long getCurrentUserId() {
return new UserService().getUserId()
.orElseThrow(() -> new AuthenticationCredentialsNotFoundException("User id not found"));
}
Example 4
private void doSomeSideEffect(final StateToSet stateToSet, final Double amount, final String stringA, final String stringB, final EnumValue enumValue) {
final ResourceA resourceA = new ResourceA.ResourceABuilder()
.withPropA(amount)
.withPropAEnumValue(ENUM_VALUE_A)
.withPropAFlag(true)
.withPropB(stringA)
.withPropC(stringB)
.build();
final Optional<ResourceB> resourceBOptional = serviceC.getResourceB(serviceC.getSomethingFromResourceA(resourceA), enumValue.name(), ValueC.name());
if (resourceBOptional.isPresent()) {
final ResourceB resourceB = resourceBOptional.get();
stateToSet.setReceiveAmount(resourceB.getPropertyD().getValue());
}
}
This example is a weird one due to the nature of only doing side effects in the function. It’s a void
method that only does a call to an external service and based on the response does another external service call and based on that response, if it’s present performs another side effect.
Even then, Optional’s provide help in this case through the method ifPresent()
, and .map()
for guarding us against problem when the property or value are not present.
private void doSomeSideEffect(final StateToSet stateToSet, final Double amount, final String stringA, final String stringB, final EnumValue enumValue) {
final ResourceA resourceA = new ResourceA.ResourceABuilder()
.withPropA(amount)
.withPropAEnumValue(ENUM_VALUE_A)
.withPropAFlag(true)
.withPropB(stringA)
.withPropC(stringB)
.build();
serviceC.getResourceB(serviceC.getSomethingFromResourceA(resourceA), enumValue.name(), ValueC.name())
.map(resourceB -> resourceB.getPropertyD())
.map(propertyD -> propertyD.getValue())
.ifPresent(value -> stateToSet.setPropertyDValue(value));
}
Conclusion
I don’t know the actual value of doing more declarative usage of Optional
s versus imperative checks besides my assessment of readability, and easier to grasp semantic. The value is specific to your team, and knowledge of the language.
In the end, I just wanted to express that Optional
s are meant to be a way to allow for more declarative code in Java. We should look to work in such a way with them.
Happy coding!