Java SE 8 Programmer II: Streams

Es gibt eine gute Zusammenfassung über Stream im Java Study Guide im Kapitel 12: Streams.
Ich möchte nicht die ganze Seite übersetzen, sondern nur die wichtigsten Punkte zusammenfassen.

Streams sind keine Collections. Sie sind unveränderbar, speichern die Elemente nicht und arbeiten lazy (wenn möglich). Streams können aus Collections, Files oder 'von Hand' erzeugt werden. Die Verarbeitung von Streams kann sequentiell oder parallel erfolgen. 

Es gibt grundsätzlich zwei Arten von Methoden, die auf Streams ausgeführt werden können: Zwischenschritte (intermediate) und abschliessende Schritte (terminal).
Während die Zwischenschritte jeweils einen Stream erzeugen, führen die abschliessenden Schritte dazu, dass sämtliche Zwischenschritte ausgeführt werden und ein Resultat erzeugt wird bzw. etwas mit dem Resultat des letzten Zwischenschritts geschieht.
Nachdem eine abschliessenden Methode auf einem Stream aufgerufen wurde, kann keine Methode auf diesem Stream mehr ausgeführt werden. Wenn dies doch versucht wird, wird eine RuntimeException ausgelöst.

Im Java Study Guide Kapitel 12 sind diese Operationen detailliert aufgelistet und erklärt.

Ein wichtiges Thema im Zusammenhang mit Streams sind Lambdas, die in einem separatem Post beschrieben werden. In Zusammenarbeit von Streams mit Lambdas beschreibt man was man tun will und nicht wie.

Wenn der Task dafür geeignet ist, kann mittels parallelStream() die Bearbeitung beschleunigt werden.
Mittels reduce(...) und collect(...) können Einträge in Streams zusammengefasst oder zusammenkopiert werden.
Der Methode reduce(...) können ein BinaryOperator zur Akkumulation und optional ein Returntyp und ein BinaryOperator als Combiner-Funktion übergeben werden.
Der Methode collect(...) können Supplier, ein BiConsumer als Akkumulator und ein BiConsumer als combiner mitgegeben werden. Diese drei Funktionalitäten können auch in einem Collector zusammengefasst werden.

  • Supplier: .get()
  • Predicate: .test(...) -> boolean, .negate(), .and(Predicate)
  • BiConsumer: .accept(T, U), .andThen(BiConsumer) -> BiConsumer
  • Comparator<T>: .compare(T, T), .comparing(Function)
  • Function<T, R>: .apply(T) -> R, andThen(Function <? super R, ? extends V> after)
  • BinaryOperator: .maxBy(Comparator), .minBy(Comparator)