2017-05-02 2 views
5

Ich möchte die fließende API von Optional verwenden und zwei Consumer s darauf anwenden.Wie sieht man auf ein Optional?

Ich träume über das so etwas wie:

Optional.ofNullable(key) 
    .map(Person::get) 
    .ifPresent(this::printName) 
    .ifPresent(this::printAddress); // not compiling, because ifPresent is void 

Wie bewerbe ich mehr Consumer s zu einem Optional, ohne es in einer temporären Variablen speichern zu müssen?

Antwort

4

können Sie diese Syntax verwenden:

ofNullable(key) 
    .map(Person::get) 
    .map(x -> {printName(x);return x;}) 
    .map(x -> {printAddress(x);return x;}); 
+3

Während dies funktioniert, ich glaube nicht, 'map' für Nebenwirkungen verwendet, ist guter Stil. Persönlich würde ich lieber mit 'ifPresent (x -> {doA (x); doB (x);})' –

+2

@RobinTopper Leute manchmal tun, weil sie versucht haben, eine Antwort auf ihre Frage selbst zu finden, aber haben es versäumt, einen zu finden, und sobald sie es herausgefunden haben, wollen sie sicherstellen, dass der nächste Sucher tatsächlich die Antwort findet. – Esko

+0

Der Grund hier ist, dass Optional ist eigentlich eine träge ausgewertete Monade (_yes, in Java_) und nur nach der Frage nach dem endgültigen Wert der internen Pipeline verarbeitet wird - wenn es keinen Wert zu Beginn ist, wird Standardverhalten aufgerufen, die möglicherweise variieren je nachdem, welche Methode zum Erhalt des endgültigen Wertes aufgerufen wurde. – Esko

6

Dies ist zwar nicht sehr Element zu sein scheint, ich beide Effekte nur in einem lambda verbinden würde und dass ifPresent passieren:

ofNullable(key) 
    .map(Person::get) 
    .ifPresent(x -> {printName(x); printAddress(x);}); 

Alternativ Sie können auch andThen verwenden, um mehrere Consumers zu verketten, obwohl dies erforderlich wäre, um die Methodenreferenz auf Consumer zu übertragen, was ebenfalls nicht sehr elegant ist.

ofNullable(key) 
    .map(Person::get) 
    .ifPresent(((Consumer) this::printName).andThen(this::printAddress)); 
+0

Ich mag es, dass Sie ein bisschen besser angehen als meins, weil es mehr * offensichtlich */lesbar macht, was tatsächlich passiert (zwei Aktionen, die nacheinander ausgeführt werden). – slartidan

1

Vielleicht so etwas wie folgt aus:

Optional.ofNullable(key) 
     .map(Person::get) 
     .ifPresent(combine(this::printAddress, this::printWish)); 

wo combine ist:

public <T> Consumer<T> combine(Consumer<T>... cs) { 
    return x -> Stream.of(cs).peek(c -> c.accept(x)).close(); 
} 
+0

Es ist ziemlich ähnlich zu '((Consumer) this :: printName) .andThen (this :: printAddress)', aber ich mag den varargs-Aspekt (es erlaubt eine beliebige Anzahl von Verbrauchern). – slartidan

+1

Sie können auch Verbraucher als Parameter von einer externen Quelle nehmen und wenn Sie 'andThen' verwenden, müssen Sie die Verbraucher auspacken und' andThen' manuell erstellen. –