Come comprendere questo metodo collect () di Java 8 Stream?


12

Stavo cercando di convertire un array int in List e ho preso la strada sconosciuta di utilizzo di Java 8 Stream e ho trovato questo

Arrays.stream(arr).boxed().collect(Collectors.toList());

Ho ancora difficoltà a comprendere appieno questa linea, principalmente,

  1. Perché Collectors.toList()in questo caso restituisce un'interfaccia di ArrayList<Integer>implementazione List? Perché no LinkedList<Integer>o qualsiasi altra classe generica conforme Listall'interfaccia? Non riesco a trovare nulla al riguardo, ad eccezione di una breve menzione di ArrayList qui , nella sezione Note API.

  2. Cosa significa il pannello di sinistra ? Ovviamente è il tipo di ritorno generico ( nel mio codice qui). E penso che sia l'argomento di tipo generico del metodo, ma come vengono specificati? Ho esaminato il documento dell'interfaccia di Collector e non sono riuscito ad assorbirlo.inserisci qui la descrizione dell'immagine Stream.collect()RArrayList<Integer><R, A>


2
1. Utilizza un elenco reale sotto il cofano, ovviamente. Ma non sarebbe saggio per un'API rivelare il tipo di Elenco sottostante effettivo. Da allora non potranno più cambiare l'implementazione in futuro. In generale, è spesso una buona idea esporre solo interfacce e mai il tipo di base reale. 2. Rè il tipo generico del tipo risultante. Ail tipo generico del tipo di accumulo intermedio del Collector. Questo è il dettaglio di implementazione di come funziona un collezionista: divide e conquista, anche per l'elaborazione parallela, raccoglie prima in tipi intermedi.
Zabuzard,

10
Non vuoi quasi mai davvero LinkedList. C'è un tweet di Josh Bloch che dice "L'ho scritto e non lo uso mai".
Andy Turner,

4
"Perché Collectors.toList()in questo caso restituisce un ArrayList<Integer>" Potrebbe non restituire un ArrayList. L' Listimplementazione non è definita , quindi non puoi fare affidamento su quale implementazione restituisce. Come dice javadoc : "Non ci sono garanzie sul tipo , la mutabilità, la serializzabilità o la sicurezza dei thread dell'elenco restituito;"
Andreas,

3
e toList()non sta restituendo un ArrayListo List- sta restituendo un Collector, che alla fine creerà e restituirà un List- anche la documentazione afferma: "... Non ci sono garanzie sul tipo , la mutabilità, la serializzazione o la sicurezza del thread dell'elenco restituito; se è necessario un maggiore controllo sull'elenco restituito, utilizzare toCollection (fornitore) .... "
user85421-Bannato

3
Consiglio vivamente la documentazione del pacchetto
Holger

Risposte:


18
  1. È un'implementazione predefinita. ArrayListviene utilizzato, perché è il migliore nella maggior parte dei casi d'uso, ma se non è adatto a te, puoi sempre definire il tuo collezionista e fornire la fabbrica Collectionche desideri:

    Arrays.stream(arr).boxed().collect(toCollection(LinkedList::new));
  2. Sì, Ae Rsono parametri generici di questo metodo, Rè il tipo restituito, Tè il tipo di input ed Aè un tipo intermedio, che appare nell'intero processo di raccolta degli elementi (potrebbe non essere visibile e non riguarda questa funzione). L'inizio di Collectorjavadoc definisce quei tipi (sono coerenti in tutto il documento):

    T - il tipo di elementi di input per l'operazione di riduzione
    A - il tipo di accumulo mutabile dell'operazione di riduzione (spesso nascosto come dettaglio di implementazione)
    R - il tipo di risultato dell'operazione di riduzione


Ok capisco. Immagino che dovrei davvero attenermi List<Integer> myList = Arrays.stream(arr).boxed().collect(Collectors.toList());e chiamare solo i metodi dichiarati nell'interfaccia Elenco su myList. Altrimenti potrei potenzialmente mettermi a rischio, se Oracle decidesse di cambiare l'implementazione predefinita in Java8u1024 o 15?
user3207158

2
@ user3207158 il metodo restituisce a List, quindi qualunque sia l'implementazione utilizzata, il comportamento è lo stesso. È improbabile che l'interfaccia venga modificata nelle nuove versioni di java.
Andronico

1
  1. Perché Collectors.toList () in questo caso restituisce un'interfaccia List che implementa ArrayList?

Come suggerisce la definizione del metodo, restituisce un'implementazione del servizio di raccolta con il fornitore del servizio di raccolta come ArrayList. Quindi, è molto chiaro dalla definizione del metodo seguente che Collectors.toListrestituisce sempre ArrayList collector ( While it's arguable why toList not toArrayList word is used in method name).

public static <T>
    Collector<T, ?, List<T>> toList() {
        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                                   (left, right) -> { left.addAll(right); return left; },
                                   CH_ID);
    }
  1. Che cosa significa il pannello di sinistra di <R, A> R collect(Collector<? super T, A, R> collector)mezzi

Se fai riferimento ai commenti della documentazione, menziona accuratamente quali sono questi tipi generici:

/*
      @param <R> the type of the result
      @param <A> the intermediate accumulation type of the {@code Collector}
      @param collector the {@code Collector} describing the reduction
      @return the result of the reduction
*/
 <R, A> R collect(Collector<? super T, A, R> collector);

Grazie Signore. Dove hai preso il codice sorgente di Collectors.toList()(primo frammento)? È openjdk?
user3207158

1
No! Ho scaricato il codice sorgente nel mio intelli j
Vinay Prajapati il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.