Wie verstehe ich diese Java 8 Stream collect () -Methode?

12

Ich habe versucht, ein int-Array in List zu konvertieren, bin den ungewohnten Weg der Verwendung von Java 8 Stream gegangen und habe mir das ausgedacht

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

Ich habe immer noch Schwierigkeiten, diese Zeile vollständig zu verstehen.

  1. Warum wird Collectors.toList()in diesem Fall eine ArrayList<Integer>Implementierungsschnittstelle zurückgegeben List? Warum nicht LinkedList<Integer>oder eine andere generische Klasse, die der ListSchnittstelle entspricht? Ich kann nichts darüber finden, außer eine kurze Erwähnung von ArrayList hier im Abschnitt API-Hinweise.

  2. Was bedeutet das linke Feld ? Offensichtlich ist der generische Rückgabetyp ( in meinem Code hier). Und ich denke, ist das generische Typargument der Methode, aber wie werden sie angegeben? Ich habe in das Collector- Interface-Dokument geschaut und konnte es nicht aufnehmen.Geben Sie hier die Bildbeschreibung ein Stream.collect()RArrayList<Integer><R, A>

user3207158
quelle
2
1. Es wird offensichtlich eine aktuelle Liste unter der Haube verwendet. Es wäre jedoch unklug für eine API, den tatsächlich zugrunde liegenden Listentyp anzugeben. Seitdem konnten sie die Implementierung in Zukunft nie mehr ändern. Im Allgemeinen ist es oft eine gute Idee, nur Schnittstellen und niemals den tatsächlichen zugrunde liegenden Typ verfügbar zu machen. 2. Rist der generische Typ des resultierenden Typs. Ader generische Typ des Zwischenakkumulationstyps des Collectors. Dies ist ein Implementierungsdetail für die Funktionsweise eines Kollektors. Er teilt und erobert, auch für die parallele Verarbeitung, und sammelt zuerst in Zwischentypen.
Zabuzard
10
Sie wollen eigentlich nie LinkedList. Es gibt einen Tweet von Josh Bloch mit der Aufschrift "Ich habe ihn geschrieben und benutze ihn nie".
Andy Turner
4
"Warum wird Collectors.toList()in diesem Fall ein zurückgegeben? ArrayList<Integer>" Möglicherweise wird kein zurückgegeben ArrayList. Die ListImplementierung ist undefiniert , sodass Sie sich nicht darauf verlassen können, welche Implementierung zurückgegeben wird. Wie der Javadoc sagt: "Es gibt keine Garantien für den Typ , die Veränderlichkeit, die Serialisierbarkeit oder die Thread-Sicherheit der zurückgegebenen Liste."
Andreas
3
und toList()gibt kein ArrayListoder zurück List- es gibt ein zurück Collector, das schließlich ein erstellt und zurückgibt List- auch in der Dokumentation heißt es: "... Es gibt keine Garantien für den Typ , die Veränderlichkeit, die Serialisierbarkeit oder die Thread-Sicherheit der zurückgegebenen Liste; Wenn mehr Kontrolle über die zurückgegebene Liste erforderlich ist, verwenden Sie toCollection (Lieferant) .... "
user85421-Banned
3
Ich empfehle dringend die Paketdokumentation
Holger

Antworten:

18
  1. Es ist eine Standardimplementierung. ArrayListwird verwendet, weil es in den meisten Anwendungsfällen am besten ist. Wenn es jedoch nicht für Sie geeignet ist, können Sie jederzeit Ihren eigenen Sammler definieren und die Fabrik nach Ihren CollectionWünschen bereitstellen :

    Arrays.stream(arr).boxed().collect(toCollection(LinkedList::new));
  2. Ja, Aund Rsind generische Parameter dieser Methode, Rist der Rückgabetyp, Tist der Eingabetyp und Aist ein Zwischentyp, der während des gesamten Prozesses des Sammelns von Elementen auftritt (möglicherweise nicht sichtbar und betrifft diese Funktion nicht). Der Anfang von Collector's Javadoc definiert diese Typen (sie sind im gesamten Dokument konsistent):

    T - die Art der Eingabeelemente für die Reduktionsoperation
    A - die veränderbare Akkumulationsart der Reduktionsoperation (oft als Implementierungsdetail verborgen)
    R - die Ergebnisart der Reduktionsoperation

Andronicus
quelle
OK, ich verstehe. Ich denke, ich sollte mich wirklich an List<Integer> myList = Arrays.stream(arr).boxed().collect(Collectors.toList());Methoden halten und nur Methoden aufrufen, die in der List-Schnittstelle auf myList deklariert sind. Andernfalls würde ich mich möglicherweise einem Risiko aussetzen, wenn Oracle beschließt, die Standardimplementierung in Java8u1024 oder 15 zu ändern.
user3207158
2
@ user3207158 Die Methode gibt a zurück. Unabhängig von der verwendeten ListImplementierung ist das Verhalten also dasselbe. Es ist unwahrscheinlich, dass die Benutzeroberfläche in neueren Versionen von Java geändert wird.
Andronicus
1
  1. Warum gibt Collectors.toList () in diesem Fall eine ArrayList-implementierende List-Schnittstelle zurück?

Wie aus der Methodendefinition hervorgeht, wird eine Collector-Implementierung mit dem Collector-Lieferanten as zurückgegeben ArrayList. Aus der nachstehenden Methodendefinition geht daher sehr deutlich hervor, dass Collectors.toListArrayList collector ( While it's arguable why toList not toArrayList word is used in method name) immer zurückgegeben wird.

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. Was bedeutet die linke Seite des <R, A> R collect(Collector<? super T, A, R> collector)Mittels

Wenn Sie sich auf Dokumentationskommentare beziehen, werden diese generischen Typen genau erwähnt:

/*
      @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);
Vinay Prajapati
quelle
Danke mein Herr. Woher hast du den Quellcode von Collectors.toList()(erstes Snippet)? Ist es openjdk?
user3207158
1
Nein! Ich habe den Quellcode in meinem Intelli J
Vinay Prajapati