2016-04-06 19 views
7

Ho il seguente problema. Diciamo che hai 2 Optional variabiliSeparazione di più variabili opzionali in Java 8

Optional<Contact> c1 = ... 
Optional<Contact> c2 = ... 

e un metodo che ha bisogno di 2 variabili di tipo Contatto

void match(Contact c1, Contact c2) {...} 

e avete bisogno di scartare sia C1 e C2 Optional Vars e passarli al metodo match().

La mia domanda è "Qual è il modo più elegante per farlo in Java 8?"

Finora ho trovato 2 modi:

  1. utilizzando isPresent

    if (c1.isPresent() && c2.isPresent()) { 
        match(c1.get(), c2.get()); 
    } 
    
  2. utilizzando ifPresent nidificato

    c1.ifPresent((Contact _c1) -> { 
        c2.ifPresent((Contact _c2) -> { 
         match(_c1, _c2); 
        }); 
    }); 
    

Entrambi i modi sono terribili secondo me ionico. In Scala posso farlo:

for { 
    contact1 <- c1 
    contact2 <- c2 
} yield { 
    match(contact1, contact2); 
} 

c'è un modo in Java 8 per farlo più ordinato di quanto descritto sopra?

+0

Che cosa vuoi fare se l'Opzionale non è presente?Ignora o fai un'eccezione? – Tunaki

+0

L'opzione IMHO 1) è più chiara del codice Scala poiché ha meno magia. –

+5

L'opzione 2 può essere scritta 'c1.ifPresent (_c1 -> c2.ifPresent (_c2 -> match (_c1, _c2)));' Inoltre, non è necessario creare blocchi. – Tunaki

risposta

5

La soluzione fornita in scala è solo zucchero di sintassi per l'utilizzo di flatMaps internamente. Puoi usare anche le flatmap in Java 8 (ma non ci sono gli effetti di sintassi). c1.flatMap(contact1 -> c2.flatMap(contact2 -> match(c1,c2)))

è quasi la stessa cosa della soluzione 2 fornita. È anche possibile utilizzare il functor applicativo da https://github.com/aol/cyclops-react (sono uno dei contributori) o qualsiasi altra libreria java funzionale 8.

functor applicativo

Optional<String> o3 = Maybe.fromOptional(o1).ap2(String::concat).ap(o2).toOptional();

Per-comprensione

Do.add(o1) .add(o2) .yield(a->b->a.concat(b));

+0

Deve essere "ifPresent" poiché la partita ha restituito il tipo void, e se la corrispondenza restituirà f.e. booleano potrebbe essere 'Opzionale result = c1.flatMap (contact1 -> c2.map (contact2 -> match (contact1, contact2)))' – klappvisor

+0

è davvero uno zucchero per la sintassi, ma rende il codice leggibile. Per quanto riguarda, cyclops-react lib, sembra fantastico, grazie per il suggerimento! – Nick

+0

In realtà, un modo migliore per farlo in scala (e senza lo zucchero di sintassi) è qualcosa come 'c1.zip (c2) .map {case (a, b) => match (a, b)}'. java ha 'zip'? – Dima

4

Si potrebbe desugar la Scala per-la comprensione per mappare/flatMap in Java 8 con una funzione come:

public static <T,V> Optional<V> map2(Optional<T> opt1, Optional<T> opt2, BiFunction<T, T, V> f) { 
     Optional<V> result = opt1.flatMap(t1 -> opt2.map(t2 -> f.apply(t1, t2))); 
     return result; 
    } 

E poi passare la funzione partita

0

Se si considera gli argomenti che non hanno valori come un'eccezione allora si potrebbe gestirli come:

try { 
    match(c1.orElseThrow(NoVal::new), c2.orElseThrow(NoVal::new)); 
} catch (NoVal ex) { 
    ... 
} 

Se non sono un caso eccezionale quindi vorrei andare con la tua prima opzione come più esplicita delle tue intenzioni. Dal mio punto di vista è abbastanza chiaro e leggibile e facile da utilizzare per utilizzare orElse se si desidera passare all'utilizzo dei valori predefiniti se gli optionals sono vuoti.