2016-06-15 25 views
5

Mam fragment kodu, w którym interfejs ma opcjonalną metodę zwracania i niektóre klasy, które implementują go, aby zwrócić coś, a inne nie.Java 8 opcjonalnie dodaje wynik zwrotny tylko, jeśli optional.isPresent

W celu wykorzystania tej Brilliant „zerowej killer”, oto co próbowałem:

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

Przepraszam za głupie, jak w tym przykładzie jest.
Jak mogę sprawdzić otrzymany zwrot i dodać go tylko jeśli jest obecny, używając opcji opcjonalnej?

P.S. Czy istnieje jakaś użyteczność dla Opcjonalnego, która jest, jeśli (X! = null) nie może zrobić?

+1

"P.S. Czy istnieje jakaś użyteczność dla Opcjonalnego, jeśli nie można (X! = Null)?" - Jestem wielkim fanem Opcjonalnego, ale jednocześnie uważam to za niemal formę komentarza.Kiedy zobaczysz coś w rodzaju Opcjonalnie, powinieneś automatycznie * wiedzieć *, że może tam nie być; jednak większość wartości, które * mogą * utrzymywać wartość null, nigdy * nie *, więc nie jest powszechną praktyką otaczanie absolutnie każdego de-odniesienia zerowymi kontrolami. –

+0

@EdwardPeters Nie chcę tego zamienić w jakąś krwawą łaźnię, ale zgadzam się z [tym gościem tutaj] (http://huguesjohnson.com/programming/java/java8optional.html): o co ci chodzi? Zgadzam się z wrażeniem "Och, opcjonalnie! Lepiej być pewnym, że rzeczywiście istnieje", ale myślę, że można było zrobić trochę lepiej. – Vale

+2

Częścią korzyści, którą widzę, jest jasność. Za każdym razem, gdy widzisz opcję "Opcjonalnie", która ma przypisaną wartość "null", * wiesz *, że jest ona nieprawidłowa i może czuć się uzasadniona w jej naprawieniu. Kiedy zobaczysz, że wartość null jest przypisana do innej wartości ... cóż, kto wie, może to jest właściwe. Uważam też, że filozoficznie: "Rzecz, która może być niczym", naprawdę powinno być innego rodzaju niż "Rzecz, która musi być czymś". Można to zrobić lepiej, ale tylko wtedy, gdy jest częścią języka od podstaw ... i, IMO, Java jest o jedną część świni do trzech części szminki. –

Odpowiedz

5

widzę, gdzie idziesz z tym - kiedy pocisk (może być lepszy niż Bullet nazwa klasy) przechodzi BallisticGelPuddy, to albo staje zatrzymany lub nie. Jeśli utknie, kumuluje się w BallisticGelPuddy.

Załóżmy przepisać kod jeśli używaliśmy null kontrole zamiast:

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

Całkiem proste, prawda? Jeśli istnieje chcemy dodać go w

Dodajmy opcjonalnego styl widok.

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

Skutecznie te dwie rzeczy osiągnąć to samo, chociaż podejście Optional jest terser.

W tym scenariuszu nie ma żadnej różnicy między tymi dwoma podejściami, ponieważ zawsze będziesz sprawdzać istnienie. Optional jest przeznaczony do ochrony przed błędami podczas obsługi null i pozwala na express a more fluid call chain, ale należy rozważyć praktyczność korzystania z Optional w tym scenariuszu. W tym przypadku nie wydaje się być konieczne.

6

Myślę, że chcesz:

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

Można też zrezygnować z pętli (zakodowanej) TOO:

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

Ale to brzydsze.

3

ze strumieniem API, można zrobić:

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

Niestety w Java 8, nie ma metody, która przekształca optionals Stream, więc trzeba go napisać samemu. Zobacz Using Java 8's Optional with Stream::flatMap

0

Chcę opublikować to na przyszłość, dla każdego, kto potknie się w problem podobny do mojego. Jeśli chcesz uzyskać dostęp do metod, które właśnie zwróciłeś, jeśli są obecne:

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