2016-05-18 13 views
6

Diciamo che ho una lista di 'A'In java 8 lambda, come accedere all'oggetto originale nello stream?

List<A> as; 

Se voglio fare un bel po 'di trasformazione su ogni A, e alla fine del trattamento, voglio prendere il risultato e metterlo in un altro campo di A, qual è il modo migliore per farlo?

cioè

as.stream(). 
map(a -> a.getX()). 
filter(x -> x != null). 
map(x -> lookup.get(x)). 

At this point how to say y -> a.setLookedUpVal(y)? 

Ho perso il riferimento a 'a' più in alto nella catena lambda. C'è un modo per memorizzarlo e rinvii ad esso o qualcosa del genere?

+1

Se la ricerca è associata a 'x ', suggerirei piuttosto di cambiare il codice per ottenere qualcosa come' a.lookup (lookup: get) '. Allora avresti un semplice 'forEach'. – zeroflagL

+1

'for (A a: as) if (a.getX()! = Null) a.setLookedUpVal (lookup.get (a.getX()));' oppure, se 'getX()' è costoso, 'per (A a: as) {X x = a.getX(); if (x! = null) a.setLookedUpVal (lookup.get (x)); } '. Confronta ogni soluzione basata su Stream con * that * prima di decidere di usarlo ... – Holger

risposta

4

Non so se è possibile accedere agli elementi non modificati, ma si potrebbe rielaborare la catena operazioni nel seguente modo:

as.stream() 
    .filter(a -> a.getX() != null) 
    .forEach(a -> a.setLookedUpVal(lookup.get(a.getX())) 

Ora capisco lo rende più complesso e potrebbe non essere interessante in risolvere il tuo problema nel mondo reale.
Tuttavia, ha il vantaggio di funzionare insieme a uno Stream<A>, che in alcune situazioni potrebbe renderlo più semplice e più estensibile rispetto a tipi diversi in passaggi diversi.

5

Se si dispone di scenario più complesso o non piace @Aaron rispondere per qualche motivo, si può fare il trucco flatMap-cattura la creazione di flusso di un elemento per ogni elemento esterno:

as.stream(). 
    flatMap(a -> Stream.of(a.getX()). 
     filter(x -> x != null). 
     map(x -> a)). 
    forEach(System.out::println); 

Qui abbiamo flusso nidificato per elemento in cui è possibile eseguire operazioni di flusso senza stato (map, filter, peek e flatMap) con riferimento all'elemento originale. Dopo che l'elemento originale non è più necessario, chiudi lo flatMap e prosegui con lo stream originale. Esempio:

Stream.of("a", "bb", "ccc", "dd", "eeee") 
    .flatMap(a -> Stream.of(a.length()) 
      .filter(x -> x > 2) 
      .map(x -> a)) 
    .forEach(System.out::println); 
// prints "ccc" and "eeee". 

O due filtri:

Stream.of("a", "bb", "ccc", "dd", "eeee") 
    .flatMap(a -> Stream.of(a.length()) 
      .filter(x -> x > 2) 
      .map(x -> a.charAt(0)) // forget the length, now check the first symbol 
      .filter(ch -> ch == 'c') 
      .map(x -> a)) // forget the first symbol, reverting to the whole string 
    .forEach(System.out::println); 
// prints only "ccc" 

Naturalmente tali scenari semplici potrebbero essere riscritte come suggerisce @Aaron, ma nei casi più complessi flatMap-cattura può essere soluzione adeguata.

+1

Oppure '.flatMap (a -> a.length()> 2 && a.charAt (0) == 'c'? Stream.of (a) : null) 'che è quasi conciso come usare' .filter' ... – Holger