Java 8可选仅在optional.isPresent时添加返回结果

时间:2016-06-15 21:51:11

标签: java java-8 optional null-check

我有一段代码,其中一个接口有一个Optional返回方法和一些实现它的类来返回一些东西,其他的不是。

为了拥抱这个出色的" null杀手",这就是我的尝试:

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>)
}}

我为这个例子多么愚蠢而道歉 我如何检查我刚刚获得的回报并仅在存在时添加它,使用可选的?

P.S。是否有任何真正有用的可选,如果(X!= null)不能做?

4 个答案:

答案 0 :(得分:11)

我知道你要去哪里 - 当一个弹丸(可能是一个比Bullet更好的类名)经过BallisticGelPuddy时,它会变得卡住或者它没有被发现。吨。如果它卡住,它会累积在BallisticGelPuddy

如果我们使用null检查,请改写代码:

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

非常简单,对吧?如果它存在,我们想要添加它。

让我们重新添加可选的样式:

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

尽管Optional方法很简单,但实际上这两件事情完成了同样的事情。

在这种情况下,两种方法之间确实没有区别,因为您总是要检查是否存在。 Optional旨在防止在处理null时出错并允许您express a more fluid call chain,但请考虑在此方案中使用Optional的实用性。对于这种情况,它似乎并非完全必要

答案 1 :(得分:9)

我想你想要:

gun.shoot().ifPresent(bullets::add);

或者您也可以免除(编码)循环:

guns.stream()
  .map(Gun::shoot)
  .filter(Optional::isPresent)
  .map(Optional::get)
  .forEach(bullets::add);

但这很丑陋。

答案 2 :(得分:3)

使用流API,您可以执行以下操作:

    List<Bullet> bullets = Arrays.stream(guns)
            .map(Gun::shoot)
            .flatMap(this::streamopt) // make Stream from Optional!
            .collect(Collectors.toList());

不幸的是,在Java 8中,没有将Optionals转换为Stream的方法,因此您需要自己编写。 见Using Java 8's Optional with Stream::flatMap

答案 3 :(得分:0)

我想发布这个以供将来参考,因为任何人都会遇到类似我的问题。您是否希望访问刚刚返回的方法(如果存在):

public class Bullet{
    private int weight = 5;
    public int getWeight(){ return weigth;}
}
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<>();
    private int totWeigth = 0;
    public void collectBullets(){
        // IF YOU WANT TO ONLY ADD WHAT YOU HAVE FOUND IN A COMPATIBLE CLASS
        // thanks to makoto and bohemian for the answers
        for(Gun gun : guns)
            gun.shoot.ifPresent(bullets::add)
        //IF YOU WANT TO ACCESS THE RETURNED OBJECT AND ADD IT TOO
        for(Gun gun : guns)
            gun.shoot.ifPresent( arg -> {totWeight += arg.getWeigth();
                                         bullets.add(arg);});
}}