Java 8 Optional API – Slayer of infamous null pointer exception

Null values and null pointer exceptions are like mosquitoes , hard to control and hated by everyone . It is a sin to use null for the purpose of error handling. Instead we must use Exceptions which are specially made for this purpose. While we cannot eliminate them completely we can handle them well .

Java 8 has introduced a new API called Optional which will make our code more flat and clean.
Optional class nicely giftwraps the object which might contain a null value. It provides methods to verify whether the object is null or not. It provides many handy functions which we will explore based on use cases.

Always write program to satisfy developer not the compiler .

Uncle Bob


Let us look at the methods that are present in Optional Class

Modifier and TypeMethod and DescriptionUseCase
static <T> Optional<T>empty()Returns an empty Optional instance.
Optional<T>filter(Predicate<? super T> predicate)If a value is present, and the value matches the given predicate, return an Optional describing the value, otherwise return an empty Optional.
<U> Optional<U>flatMap(Function<? super T,Optional<U>> mapper)If a value is present, apply the provided Optional-bearing mapping function to it, return that result, otherwise return an empty Optional.
Tget()If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException.#1
voidifPresent(Consumer<? super T> consumer)If a value is present, invoke the specified consumer with the value, otherwise do nothing.#
booleanisPresent()Return true if there is a value present, otherwise false.#1
<U> Optional<U>map(Function<? super T,? extends U> mapper)If a value is present, apply the provided mapping function to it, and if the result is non-null, return an Optional describing the result.#5
static <T> Optional<T>ofNullable(T value)Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.#3
TorElse(T other)Return the value if present, otherwise return other.#3
TorElseGet(Supplier<? extends T> other)Return the value if present, otherwise invoke other and return the result of that invocation.#3
<X extends Throwable>
T
orElseThrow(Supplier<? extends X> exceptionSupplier)Return the contained value, if present, otherwise throw an exception to be created by the provided supplier.#4
References : https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

Use Case #1 : You are consuming a third party API which can give you a null object .

Let us take a small example. There is a simple method which does some processing . There is nothing wrong in the code below , it works fine .

public String getSomeData(ResponseDTO resp){
   if( resp!=null ){
   // Some error handling logic 10 lines
   }else{
   // some other logic etc 20 lines
   }
}
// after serveral months
public String getSomeData(ResponseDTO resp){
   if( resp!=null ){
   // Some error handling logic 20 lines
   }else{
   // some other logic e40 lines
   }
}

After several months into the project , many people would have tweaked the code within the if / else block adding some more conditions . At this point code starts smelling a little like a rotten fish. On top of this the application starts throwing null pointer exception every now and then in production . The developer is frantically debugging the code to find out which object is null and at which point.

// after serveral months
public String getSomeData(ResponseDTO resp){
if( resp!=null && resp.getName() && resp.getName()... ){
// Some error handling logic 20 lines
}else{
// some other logic e40 lines
}
}

Somewhere along the line , the main business logic which the application intends to solve gets buried in this mess of ifs/else/elseif/ nested blocks, making the whole code base dirty and complicated .

Let us use the Optinal In this case .

public String getSomeData(ResponseDTO resp){
   Optional<ResponseDTO> resp = OptionalOfNullable(resp);
   if (resp.isPresent())
       return resp.get().getName();
}

Anyone can understand and guess the intent of the code . You are telling the compiler to check whether the object is present or not. Lines in the code describe themselves nicely . This style of programming is called as “Declarative Programming’.

Use Case #2 : Check for null values and throw an exception

You are trying to fetch a record from database or from some data source. If the data is empty /not present then we should show exception appropriately.

public Record getData(query) {
         Optional rec = Optional.ofNullable(recordparam);
         return rec.orElseThrow(RecordNotFoundException::new);
 }

Use Case #3 : Returning a default value

In many scenarios, we would want to return a default value if some resource/object is not present.
Optional class has this feature baked-in and we can do this in one line .

public String getLastCount (String id){
     //logic to fetch from db
     Optional  rec = Optional.ofNullable(result);
     return rec.orElse(0);
 }

The above code returns default value of 0 when value is not found.
In addition , there is one more method orElseGet ,where you can use a specifier instead of a static value and call some other method to arrive at the default value .

public String getLastCount (String id){
     //logic to fetch from db
     Optional  rec = Optional.ofNullable(result);
     return rec.orElseGet(()->{
         return 123;
     });
 }
 

Use Case #4: Throwing meaningful exceptions

At times , we would want to throw an error if you don’t get the value you are expecting for which we generally write a code like this :

public User getUser(String userId){
     //code to get the user ID 
     Optional user = Optional.ofNullable(fetchFromDb(userId));
     retrun user.orElseThrow( UserNotFoundException() )
 }

Similarly , just like in Use case #3 , we can also pass a supplier and call other methods / logging .

Use Case #5 : Getting the nested objects

When it comes to nested objects we keep writing the code like this:

String id = null;
if( university != null && university.getCollege()!=0 && university.getCollege().getId!=null){
     this.id = university.getCollege().getId();
 }

Merely to get the value of Id we have written one if block with many conditions . The same thing can be done seamlessly using map method in Optional like this :

String id = Optional.ofNullable(univeristy)
                    .map(university::getCollege)
                    .map(college::getId)
                    .orElseThrow( CollegeNotFoundException::new);

srnyapathi
srnyapathi
Articles: 41