Java 8 optional add return result only if optional.isPresent

Vale picture Vale · Jun 15, 2016 · Viewed 20.6k times · Source

I have a piece of code where an interface has an Optional return method and some of the classes that implement it to return something, other don't.

In an effort to embrace this brilliant "null killer", here is what I have tried:

public interface Gun {
    public Optional<Bullet> shoot();
}

public class Pistol implements Gun{
    @Override
    public Optional<Bullet> shoot(){
        return Optional.of(this.magazine.remove(0)); 
    }//never mind the check of magazine content
}

public class Bow implements Gun{
    @Override
    public Optional<Bullet> shoot(){
        quill--;
        return Optional.empty();
    }
}

public class BallisticGelPuddy{
    private Gun[] guns = new Gun[]{new Pistol(),new Bow()};
    private List<Bullet> bullets = new ArrayList<>();
    public void collectBullets(){
        //here is the problem
        for(Gun gun : guns)
            gun.shoot.ifPresent(bullets.add( <the return I got with the method>)
}}

I apologise for how silly this example is.
How can I check the return I just got and add it only if present, using optional?

P.S. is there any real usefulness to Optional which is if(X != null) couldn't do?

Answer

Makoto picture Makoto · Jun 16, 2016

I see where you're going with this - when a projectile (may be a better class name than Bullet) goes through BallisticGelPuddy, it either becomes stuck or it doesn't. If it gets stuck, it accumulates in BallisticGelPuddy.

Let's rewrite the code if we were using null checks instead:

for(Gun gun: guns) {
    final Bullet bullet = gun.shoot();
    if(bullet != null) {
        bullets.add(bullet);
    }
}

Pretty straightforward, right? If it exists we want to add it in.

Let's add the optional style back in:

for(Gun gun: guns) {
    gun.shoot().ifPresent(bullets::add);
}

Effectively these two things accomplish the same thing, although the Optional approach is terser.

In this scenario, there's really no difference between the two approaches since you're always going to be checking for existence. Optional is meant to guard against mistakes when handling null and allows you to express a more fluid call chain, but consider the practicality of using Optional in this scenario. It doesn't seem entirely necessary for this case.