How to defensively code Optional parameters in Java

Let’s start with the assumption that null is evil. There are a million posts out there on this topic, so I won’t beat a dead horse on that.

Note: I wrote up some source code with unit tests for this example. You can find that here: https://github.com/davidmerrick/defensive-optionals.

Say you have this Cat object. A cat, naturally, can optionally have laser vision.

public class Cat {
    public Optional<LaserVision> laserVisionOptional;
}
public class LaserVision {
    public void shootLasers(){
        System.out.println("pew pew pew!");
    }
}

All good, right? Well, what if you did this?

@Test
public void noLaserVisionByDefault(){
    Cat cat = new Cat();
    boolean hasLaserVision = cat.laserVisionOptional.isPresent();
    Assert.assertFalse(hasLaserVision);
}

D’oh!

java.lang.NullPointerException
	at com.davidmerrick.CatTest.noLaserVisionByDefault(CatTest.java:10)
	at java.base/

That Optional parameter is initialized to null. Which sort of defeats the purpose of using an Optional in the first place.

We can solve this by initializing the object to Optional.empty().

public class Cat {
    public Optional<LaserVision> laserVisionOptional = Optional.empty();
}

Now, our noLaserVisionByDefault() test passes. But, we’re not quite done. What if someone inadvertently sets that parameter to null?

@Test
public void noLaserVisionByDefault(){
    Cat cat = new Cat();
    cat.laserVisionOptional = null;
    boolean hasLaserVision = cat.laserVisionOptional.isPresent();
    Assert.assertFalse(hasLaserVision);
}

Argh!

java.lang.NullPointerException
	at com.davidmerrick.CatTest.noLaserVisionByDefault(CatTest.java:12)

The way to defend against this is to make the laserVisionOptional parameter private, then enforce its value via a setter.

public class Cat {

    private Optional<LaserVision> laserVisionOptional = Optional.empty();

	public void setLaserVisionOptional(Optional<LaserVision> laserVisionOptional) {
        if(laserVisionOptional != null){
            this.laserVisionOptional = laserVisionOptional;
        }
    }

    public Optional<LaserVision> getLaserVisionOptional() {
        return laserVisionOptional;
    }
}

Now, even if someone tries to set that parameter to null, it will instead be set to Optional.empty().

For extra convenience, we can add an overloaded setter that allows us to just pass in a LaserVision object directly.

public void setLaserVisionOptional(LaserVision laserVision) {
	this.laserVisionOptional = Optional.ofNullable(laserVision);
}

Notice that this code is also written defensively by using Optional.ofNullable().

tl;dr

  • null is bad.
  • Defensive coding is good.
  • protect your Optional parameters from being null by initializing them and by enforcing their values via setters.

Updated:

Comments