Java Optional in class fields? Why not.
Marcin Piczkowski
Posted on October 26, 2018
Optional was introduced in Java 8 and according to documentation it is
supposed to limit the use of null
in return from the methods.
Optional
class is not serializable so it is not intended to be used as fields
in Java beans.
As Brian Goetz stated on Stack Overflow
"routinely using it as a return value for getters would definitely be over-use."
I agree with the statement that they should be used with care and definitely not as a panacea for all problems.
I happened to see using Optional
in such contexts like below to avoid using if-else statements in favour of more functional-style programming flow:
Optional.ofNullable(aField)
.map(this::doSthWithTheField)
.orElse(this::doSthElse)
versus old good imperative style:
if(aField==null){
doSthWithTheField(aField);
}else{
doSthElse(aField);
}
Is this usage of Optional
already an overuse or not?
I think it's a matter of taste, pragmatism and an agreement in a team.
It's sort of messy in my oppinion if somestimes if-else and sometimes the structure like above is used around the single project cource code.
Personally I like more the version with Optional
.
How about the crazy idea of using Optionals in your Domain Transfer Object (DTO)?
Or is it no so crazy at all?
Read further to check if this approach makes sense for you.
Imagine you have a business domain with a class User
like below:
class User{
private String name;
private String secondName;
public String getName(){
return name;
}
public Optional<String> getSecondName(){
return Optional.ofNullable(name)
}
// skipped setters for readability
}
Your User
has attributes like name
which is required (not null), and secondName
which can be empty.
Having this, you do not need to worry anywhere else that you can get second name which is null
.
E.g. you could use it like that:
User user = ...
String userName = user.getName();
String displayedName = user.getSecondName()
.map(s-> userName + ", " + s)
.orElse(userName);
instead of:
User user = ...
String userName = user.getName();
String second = user.getSecondName();
String displayedName = null;
if(second != null){
displayedName = userName + ", " + second;
} else {
displayedName = userName;
}
See the difference? Moreover, when you look at the domain class getters you already know which fields are optional, your code is self-documenting.
Now what if you need to pass such domain object in the response from a controller?
Usually you would probably like to wrap it in a Domain Transfer Object, like UserResponse
but for simplicity, let's assume you will return User
in the controller.
How will Spring know how to convert the Optional
value into JSON?
Well.. it won't by default. It would take the public getter method of the Optional
class which is isPresent()
and use it in JSON, e.g.:
{"name":"Marcin","secondName":{"present":true}}
To allow the correct conversion Jackson library has a module dedicated for Java 8 types.
Using Maven we need to ad this dependency:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.9.6</version>
</dependency>
and register it in ObjectMapper
like this:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
The good news is that if you're using Spring Boot with spring-boot-starter-web
dependency then it already has everything configured and ready for use :)
Here is a demo for this post.
If you liked it, you may also like other references:
Posted on October 26, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.