AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

Java Optional and best practices

Since Java 8 appeared a few years ago, along with the introduction of Optional, I have seen many instances of misuse or incorrect use of Optional. In this post, we will discuss Java Optional and best practices, as using Optional correctly is not an option ;).

Brian Goetz provided a good definition of Java Optional in response to a question:

Question: Is it good practice to return Optional<Foo> instead of Foo, considering that the value can be null?

Answer:

Of course, people will do what they want. But we did have a clear intention when adding this feature, and it was not to be a general-purpose Maybe type, as much as many people would have liked us to do so. Our intention was to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result”, and using null for such was overwhelmingly likely to cause errors.

For example, you probably should never use it for something that returns an array of results or a list of results; instead, return an empty array or list. You should almost never use it as a field of something or a method parameter.

I think routinely using it as a return value for getters would definitely be overuse.

There’s nothing wrong with Optional that it should be avoided; it’s just not what many people wish it were, and accordingly, we were fairly concerned about the risk of zealous overuse. Brian Goetz

Essentially, what Brian Goetz is saying in this quote is that Optional should not be excessively used, and it’s not bad to avoid its use. It should not be used for getters, lists, or wrapping any object.

Now let’s take a look at a few things we often do with Optional that we should avoid or refrain from using Optional in those cases. Here we go:

Best Practices with Optional

Avoid assigning null to an Optional

One common excessive use of Optional is when we try to use it in the traditional way by assigning null to an Optional:

Optional<User> user = null;

If you need something like the above, it’s better to assign it to empty or not use it:

Optional<User> user = Optional.empty();

Avoid using Optional in Constructors

Keep in mind that Optional is essentially a wrapper, so using it within a constructor adds unnecessary complexity:

Avoid doing this:

public class Car {
    private final String model;       
    private final Optional<String> color;
    public Car(String model, Optional<String> color) {
        this.model = model;
        this.color = color;
    }

}

Better to do it this way:

public class Car {
    private final String model;       
    private final String color;
    public Car(String model, String color) {
        this.model = model;
        this.color = color;
    }

}

Avoid using Optional with Lists

It is not recommended to create an Optional of a list since if the list is null, Optional would also be null, and its handling becomes more complex.

Avoid:
Optional<List<String>> cars = Optional.of(List.of("ford","renault");

Use:
List<String> cars = List.of("ford","renault");

Avoid using Optional as a parameter in a method

Passing a parameter with Optional in a method is counterproductive as it requires adding conditional logic to handle this parameter. Let’s see an example:

Avoid:

public void car(Optional<String> models) {

    if (models.isPresent()) {
        doSomething(models.get());
    } else {
        doSomethingElse();
    }
    
}

Better option:

public void car(String models) {

    if (null != models) {
        doSomething(models);
    } else {
        doSomethingElse();
    }
    
}

The previous one would be a better option; you can see that the code is quite similar, but computationally speaking, you’re creating an unnecessary wrapper, which is more costly for the compiler.

Using orElse() or orElseThrow() instead of isPresent() or get()

Instead of having to go through multiple steps to retrieve a value, we can use lambda expressions to chain operations and obtain the value.

Avoid:

List<Car> cars = //lista de coches;
Optional<Car> findCar = cars.stream()
    .filter(car -> c.getColor().equalsIgnoreCase("blue")
    .findFirst();

if (findCar.isPresent()) {
    return findCar.get().getModel();
} else {
    return throw new NotFoundExcepcion("Car blue not found");
}

A better option would be:

List<Car> cars = //lista de coches;
Optional<Car> findCar = cars.stream()
    .filter(car -> c.getColor().equalsIgnoreCase("blue")
    .findFirst()
   .map(Car::getModel)
  .orElseThrow(()-> new NotFoundException("Car blue not found")

Whenever possible, avoid using .isPresent() and chain the operations instead.

Avoid using Optional as a ternary operator

We might think that Optional can be a solution to avoid dealing with null values, but if we apply Optional everywhere, our code becomes more verbose.

Avoid:

    return Optional.ofNullable(value).orElse("BLUE");

Better

return value == null ? "BLUE" : value;

Avoid using Optional when returning a method’s value

We should avoid returning a method with an Optional.

Avoid:

public Optional<List<String>> getDoctors(String name) {
    Hospital hospital = new Hospital (List.of("Pepe", "Juan"))      
    List<String> doctors = hospital.getDoctors(); 
    return Optional.ofNullable(doctors);
}

Better:

public List<String> getDoctors(String name) {
    Hospital hospital = new Hospital (List.of("Pepe", "Juan"))      
    List<String> doctors = hospital.getDoctors(); 
    return doctors!= null ? items: Collections.emptyList();
}

There’s no need to use Optional to return an empty list or return a method as Optional to avoid null values; it should be checked beforehand.

Don’t confuse between Optional.of() and Optional.ofNullable()

It’s quite common to misuse these two concepts. Just remember that Optional.of(null) will throw a NullPointer exception, while Optional.ofNullable(null) will result in Optional.empty().

Avoid:

public Optional<String> getModelCar() {

           String modelCar = null;
 
           return Optional.of(modelCar); 
}

If modelCar is null, it will throw a NullPointer exception.

Better:

public Optional<String> getModelCar() {

           String modelCar = null;
 
           return Optional.ofNullable(modelCar); 
}

When you’re certain that there’s a value, then use Optional.of("something").

Consume an Optional if present, otherwise perform an empty action

Using ifPresentOrElse with Optional is a good alternative to isPresent() and get().

Avoid:

Optional<String> modelCar = ... ;
if(modelCar.isPresent()) {
    System.out.println("Model is: " + modelCar.get());
} else {
    System.out.println("Model not found");
}

Better:

Optional<String> modelCar = ... ;
modelCar.ifPresentOrElse(
    System.out::println, 
    () -> System.out.println("Model not found")
);

Return null with orElse() instead of using isPresent() and else

If we ever need to return null when an Optional doesn’t have a value, it’s better to use the orElse() option instead of using ifPresent() followed by an else statement:

Avoid:

Optional<String> modelCar = ... ;
if(modelCar.isPresent()) {
    return modelCar.get()
} else {
    return null;
}

Better

Optional<String> modelCar = ... ;
return modelCar.orElse(null);

Avoid using Optional<T> and use its generics OptionalInt, OptionalLong, or OptionalDouble

If you need to use an Optional for an int, long, or double, it’s better to use OptionalInt, OptionalLong, or OptionalDouble. They are computationally less expensive, simplify the code, and are considered best practices:

Avoid:

Optional<Long> value = Optional.of(1L);
Optional<Double> value = Optional.of(1.5d);
Optional<Integer> value = Optional.of(1);

Better

OptionalDouble value = OptionalDouble.of(1.5d);  
OptionalLong value = OptionalLong.of(1L);       
OptionalInt value = OptionalInt.of(1);           

Conclusion

In this post, we have tried to analyze the options we have with Java Optional and best practices to make better use of Optional.

If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!

Leave a Reply

Your email address will not be published. Required fields are marked *