web-dev-qa-db-ja.com

Java 8オプションの追加は、オプションの場合にのみ結果を返します。isPresent

インターフェイスにオプションのreturnメソッドがあり、それを実装して何かを返すクラスがあるクラスとないクラスがあるコードがあります。

この見事な「null killer」を受け入れるために、私が試したのは次のとおりです。

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

この例が愚かであることをお詫びします。
オプションを使用して、取得した返品を確認し、存在する場合にのみ追加するにはどうすればよいですか?

追伸Optionalには、if(X!= null)で実行できない実際の有用性はありますか?

10
Vale

私はこれであなたがどこへ向かっているのか分かります-発射物(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のアプローチはより簡潔ですが、これら2つのことで実質的に同じことを実現できます。

このシナリオでは、常に存在をチェックするため、2つのアプローチに違いはありません。 Optionalnullを処理するときの間違いを防ぐためのもので、 より流動的な呼び出しチェーンを表現する を可能にしますが、Optionalの使用の実用性を考慮してくださいこのシナリオでは。この場合、それは完全に必要とは思われません。

16
Makoto

私はあなたが望むと思います:

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

または、(コード化された)ループも省略できます。

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

しかし、それは醜いです。

12
Bohemian

ストリームAPIを使用すると、次のことができます。

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

残念ながら、Java 8には、OptionalをStreamに変換するメソッドがないため、自分で記述する必要があります。 sing Java 8's Stream :: flatMap のオプション

3
user140547

私がこれと同じような問題につまずいた人のために、今後の参考のためにこれを投稿したいと思います。存在する場合は、返されたばかりのメソッドにアクセスする必要があります。

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);});
}}
0
Vale