DEV Community

loading...

Java Optional in class fields? Why not.

piczmar_0 profile image Marcin Piczkowski ・3 min read

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 :)

Spring dependencies

Here is a demo for this post.

If you liked it, you may also like other references:

Discussion (0)

pic
Editor guide