2014-11-13 4 views
16

consente di dire che abbiamo questo pezzo noioso di codice che tutti abbiamo dovuto usare:Come utilizzare la chiamata di raccolta in Java 8?

ArrayList<Long> ids = new ArrayList<Long>(); 
for (MyObj obj : myList){ 
    ids.add(obj.getId()); 
} 

Dopo il passaggio a Java 8, mio ​​IDE mi sta dicendo che posso sostituire questo codice con collect call, e si auto-genera :

ArrayList<Long> ids = myList.stream().map(MyObj::getId).collect(Collectors.toList()); 

Tuttavia la sua dandomi questo errore:

collect(java.util.stream.Collector<? super java.lang.Long,A,R>) in Steam cannot be 
applied to: (java.util.stream.Collector<T>, capture<?>, java.util.List<T>>) 

ho provato gettando il parametro, ma la sua dandomi indefinita A e R e l'IDE non fornisce ulteriori suggerimenti.

Sono curioso di sapere come si può usare collect call in questo scenario e non sono riuscito a trovare alcuna informazione che potesse guidarmi correttamente. Qualcuno può far luce?

risposta

37

Il problema è che Collectors.toList, non a caso, restituisce un List<T>. Non è un ArrayList.

List<Long> ids = remove.stream() 
     .map(MyObj::getId) 
     .collect(Collectors.toList()); 

programma al interface.

Dalla documentazione:

Returns a Collector that accumulates the input elements into a new List . There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned; if more control over the returned List is required, use toCollection(Supplier) .

enfasi è mia - non si può nemmeno supporre che il List restituito è mutevole, e tanto meno che si tratta di una classe specifica. Se si desidera un ArrayList:

ArrayList<Long> ids = remove.stream() 
     .map(MyObj::getId) 
     .collect(Collectors.toCollection(ArrayList::new)); 

Si noti inoltre, che si è soliti utilizzare import static con l'API Java 8 Stream in modo da aggiungere:

import static java.util.stream.Collectors.toCollection; 

(io odio preferiti import static, non fa altro che inquinare lo spazio dei nomi e aggiungere confusione.Ma selettiva import static, specialmente con i Java 8 classi di utilità, può ridurre notevolmente codice ridondante)

comporterebbe:

ArrayList<Long> ids = remove.stream() 
     .map(MyObj::getId) 
     .collect(toCollection(ArrayList::new)); 
+0

In realtà il codice risultato non è più breve o molto più significativo di quello che abbiamo fatto prima di Java8, hmm e le prestazioni? – azerafati

+4

@Bludream non si tratta di essere più brevi o più significativi, si tratta di introdurre un nuovo paradigma nella programmazione funzionale di Java. Questo ti permette di fare le cose in un modo molto diverso dalle precedenti iterazioni di Java. La programmazione funzionale ha le sue caratteristiche quando è necessario astrarre _behaviour_ piuttosto che _data_. Inoltre, questo sopra potrebbe essere un monotipo leggermente lungo; non era certamente possibile farlo in una riga in precedenza. –

+0

Vedo, ma come l'OP cercavo anche qualcosa per sostituire i miei collezionisti che si diffondevano ovunque nel mio codice. – azerafati

2

uso un sacco di blocchi collettore dove Creo un array vuoto e riempirlo usando un ciclo così ho deciso ho bisogno di una classe di utilità della mia di non scrivere di nuovo le stesse linee pubblicità di nuovo, qui si tratta di:

public class Collections { 

    public static <T, O> List<T> collect(Set<O> items, Function<? super O, ? extends T> mapper) { 

    return items.stream().map(mapper).collect(Collectors.toCollection(ArrayList::new)); 
} 

}

e utilizzarlo come questo

List<Product> prods = Collections.collect(basket.getOrderItems(), OrderItem::getProduct); 

o come questo

List<Long> prods = Collections.collect(basket.getOrderItems(), (item)->item.getProduct().getId()); 

Anche se potrebbe sembrare molto più facile da leggere, sembra flussi sono un po 'più lento in questo tipo di scenari, look here

+0

È possibile utilizzare 'Item :: getProduct'. Imparare ad usare correttamente i riferimenti al metodo è una parte importante dell'apprendimento di Java 8. L'aggiunta di un 'import static' rimuove anche la necessità di fare riferimento al metodo direttamente. –

+0

sì, grazie! Ho funzionato come dicevi, e odio anche usare 'import static'! – azerafati