2014-10-28 17 views
6

Sto provando a flatMapOptional s in Java. Ecco un esempio semplificato:Java 8 flatMap + Optional.of non viene compilato

List<String> x = Arrays.asList("a", "b", "c"); 
List<String> result = x.stream().flatMap((val) -> val.equals("b") ? Optional.empty() : Optional.of(val)).collect(Collectors.toList()); 

ottengo questo messaggio di errore del compilatore:

Error:(10, 27) java: incompatible types: no instance(s) of type variable(s) T exist so that java.util.Optional<T> conforms to java.util.stream.Stream<? extends R> 

Cosa c'è di sbagliato? Ecco un esempio di quello che sto cercando di realizzare in Scala:

List("a", "b", "c").flatMap(x => if (x == "b") None else Some(x)) 

Restituisce:

res2: List[String] = List(a, c) 

come previsto.

Come si converte questo in Java in modo che venga compilato?

risposta

2

Non v'è alcuna necessità di trattare con Optional qui.

La soluzione straight-forward più semplice è quello di utilizzare filter

List<String> result = x.stream() 
    .filter(val -> !val.equals("b")) 
    .collect(Collectors.toList()); 

Se ti ostini a usare flatMap, si dovrebbe utilizzare semplicemente Stream invece di Optional:

List<String> result = x.stream().flatMap(
    val -> val.equals("b")? Stream.empty(): Stream.of(val)) 
    .collect(Collectors.toList()); 

Se avete a che fare con un'operazione che produce inevitabilmente un Optional, sarà necessario convertirlo in un Stream per l'utilizzo di Stream.flatMap:

List<String> result = x.stream() 
    .map(val -> val.equals("b") ? Optional.<String>empty() : Optional.of(val)) 
    .flatMap(o->o.map(Stream::of).orElse(Stream.empty())) 
    .collect(Collectors.toList()); 
6

flatMap mappa un elemento dell'input Stream in un diverso Stream. Pertanto deve restituire uno Stream e non uno Optional.

Pertanto, si dovrebbe fare qualcosa di simile:

List<String> x = Arrays.asList("a", "b", "c"); 
List<Optional<String>> result = 
    x.stream() 
    .flatMap((val) -> 
        val.equals("b") ? Stream.of(Optional.empty()) : 
            Stream.of(Optional.of(val))) 
    .collect(Collectors.toList()); 

Si noti che se il tuo obiettivo è semplicemente quello di sbarazzarsi di alcuni dei valori ("b" nel tuo esempio), non è necessario per utilizzare Opzionale a tutti. Si può solo filtrare la Corrente:

List<String> result = 
    x.stream() 
    .filter (val -> !val.equals("b")) 
    .collect(Collectors.toList()); 

In questo modo non è necessario flatMap e l'output è un List<String> invece di un List<Optional<String>>.

Come Holger commentati, la soluzione che restituisce un Stream di Optional s può essere semplificato utilizzando map anziché flatMap, poiché ogni elemento è mappato in un unico Optional:

List<String> x = Arrays.asList("a", "b", "c"); 
List<Optional<String>> result = 
    x.stream() 
    .map((val) -> val.equals("b") ? Optional.empty() : Optional.of(val)) 
    .collect(Collectors.toList()); 
+0

Grazie! Normalmente filtrerei. In questo caso (il caso reale, non l'esempio di giocattolo semplificato) preferirei usare Optionals perché il filtraggio significherebbe scavare un sacco di cazzate che dovrò fare anche nella fase di mappa. – auramo

+1

Quando ogni elemento del flusso è mappato esattamente a un 'Opzionale', non è necessario usare' flatMap'. Basta usare '.map (val -> val.equals (" b ")? Optional.empty(): Opzionale.di (val)) ' – Holger

+0

@Holger Hai assolutamente ragione. Non ci ho pensato. Stavo seguendo la decisione dell'OP di utilizzare un flatMap. – Eran