13

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

为了拥抱这个出色的“空杀手”,我尝试了以下方法:

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

我为这个例子多么愚蠢而道歉。
我怎样才能检查我刚刚得到的回报,只有在存在时才添加它,使用可选的?

PS 是否对 Optional 有任何真正的用处,这是 if(X != null) 无法做到的?

4

4 回答 4

23

我知道你的目标是什么——当一个射弹(可能是一个比 更好的类名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并允许您表达更流畅的调用链,但要考虑Optional在这种情况下使用的实用性。对于这种情况,这似乎并不完全必要。

于 2016-06-15T22:00:54.427 回答
13

我想你想要:

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

或者您也可以省去(编码)循环:

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

但它更丑。

于 2016-06-15T21:57:32.560 回答
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 的方法,因此您需要自己编写。请参阅将 Java 8 的 Optional 与 Stream::flatMap 一起使用

于 2016-06-15T22:08:19.727 回答
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);});
}}
于 2016-06-16T08:24:09.307 回答