How to use Optional keyword to avoid NullPointerException in nested objects in Java?

Let’s say you have a nested object in your application .

And you want to retrieve the value of a field in the deepest nested object.

We will see how to do this using pre-Java 8 and post-Java 8 code (using Optional keyword)

Lets consider an Employee object,

Let’s say the Employee object has an address which in turn has an object state which in turn has an object district which in turn has an object taluk which in turn has values like name , street name and pincode.

Here are the classes representing each object:

Employee.java


package com.optional;


public class Employee{


    String name;

    Address address;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

Address.java

package  com.optional;

public  class Address{

    State state;

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }
}

State.java

package com.optional;

public class State{


    String name;

    District district;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public District getDistrict() {
        return district;
    }

    public void setDistrict(District district) {
        this.district = district;
    }
}

District.java

package com.optional;

public class District{


    String name;

    Taluk taluk;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Taluk getTaluk() {
        return taluk;
    }

    public void setTaluk(Taluk taluk) {
        this.taluk = taluk;
    }
}

Taluk.java


package com.optional;

public class Taluk{

    String name;

    String street;

    int pinCode;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPinCode() {
        return pinCode;
    }

    public void setPinCode(int pinCode) {
        this.pinCode = pinCode;
    }
}

Now say you want to get the pincode of an employee.

You may do something like this :

int pincode = employee.getAddress().getState().getDistrict().getTaluk().getPinCode();

But any of the nested object in the above code can be null.

So to avoid NullPointerException , you may do something like this traditionally:

   if (employee != null) {


            Address address = employee.getAddress();

            if (address != null) {

                State state = address.getState();

                if (state != null) {

                    District district = state.getDistrict();

                    if (district != null) {

                        Taluk taluk = district.getTaluk();

                        return taluk.getPinCode();
                    }
                }
            }
        }
return 0;

That is a lot of checks and a lot of code!

To avoid this , let’s make use of Optional keyword introduced in Java 8.

In the getter method of each nested object , wrap the object using Optional.ofNullable() method and return the Optional instead of the actual object.

Optional.ofNullable() accepts null values and converts the given object to an Optional object. If null value is present it returns an empty Optional. To retrieve the actual object you need to call get() method on the Optional object.

Below are the classes refactored with the getters returning Optional objects instead of the actual object:

Employee.java


package com.optional;


import java.util.Optional;

public class Employee{


    String name;

    Address address;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Optional<Address> getAddress() {
        return Optional.ofNullable(address);
    }

    public void setAddress(Address address) {
        this.address = address;
    }
}

Address.java

package  com.optional;

import java.util.Optional;

public  class Address{

    State state;

    public Optional<State> getState() {
        return Optional.ofNullable(state);
    }

    public void setState(State state) {
        this.state = state;
    }
}

State.java

package com.optional;

import java.util.Optional;

public class State{


    String name;

    District district;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Optional<District> getDistrict() {
        return Optional.ofNullable(district);
    }

    public void setDistrict(District district) {
        this.district = district;
    }
}

District.java

package com.optional;

import java.util.Optional;

public class District{


    String name;

    Taluk taluk;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Optional<Taluk> getTaluk() {
        return Optional.ofNullable(taluk);
    }

    public void setTaluk(Taluk taluk) {
        this.taluk = taluk;
    }
}

Now if you want to get the pincode of an employee , you can do it using a single line of code:

        int pin = Optional.ofNullable(employee)
                .flatMap(emp -> emp.getAddress())
                .flatMap(addr -> addr.getState())
                .flatMap(state -> state.getDistrict())
                .flatMap(dist -> dist.getTaluk())
                .map(taluk -> taluk.getPinCode()).orElse(0);

We haven’t even used isPresent() and get() methods of Optional !

Let’s look at this code in detail:

First you wrap an employee object using Optional.ofNullable() method . This returns an Optional<Employee> object.

You then extract the address out of employee object using flatMap() of Optional class.

Since address is also an optional object , calling just the map() method would return an Optional<Optional<Address>> object :

Optional.ofNullable<employee> --> Optional<Employee>
Optional<Employee>.map(emp -> emp.getAddress()) --> Optional<Optional<Address>>

So instead we can use the flatMap() method which reduces the object to a single optional:

Optional<Employee>.flatMap(emp -> emp.getAddress()) -> Optional<Address>

If address is empty we get an empty optional back , else we get the address object wrapped as Optional object.

We further navigate through the nested objects using flatMap() method.

Finally when we reach the taluk object , we use map() method to get the pincode from taluk object .

(Since pincode is not wrapped by Optional we use map() method instead of flatMap())

The map() method returns the pincode wrapped by an Optional object.

And then on the resulting Optional object , we call orElse() method.

If pincode is present the orElse() method returns the value present in the Optional object (which is the pincode)

If the pincode is null , the orElse() method returns whatever value is passed to it as a parameter (in our case it is 0)

Instead of orElse() you can also use orElseThrow() method to throw an exception if pincode is null.

That’s it!

We have seen one benefit of using Optional keyword in Java.


Posted

in

by

Comments

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading