Advanced   Java   Services Collector Back Next Up Home


Collector<T,A,R> und Stream<T>

Collector ist ein Interface mit zwei statischen Factorymethoden mit denen man Instanzen vom Typ Collector erstellen kann. Eine Instanzen dieses Typs übergibt man dann der Methode <R,A> R collect(Collector<? super T,A,R> collector) aus Stream<T>.

Die Bedeutung der generischen Typen kann man am besten über die Signatur der zwei statischen Factorymethoden erläutern.


Die 4 + 1 Methode (4 obligatorische Parameter + 1 optionaler Parameter)

Die Methode hat die folgende Form

static <T,A,R> Collector<T,A,R> of(Supplier<A>       supplier,
                                   BiConsumer<A,T>   accumulator,
                                   BinaryOperator<A> combiner,
                                   Function<A,R>     finisher,
                                   Collector.Characteristics... characteristics)

Die Bedeutung der Parameter

Supplier<A>       liefert einen Behälter vom Typ A, der Elemente vom Typ T aufnehmen kann

BiConsumer<A,T>   bringt Elemente vom Typ T in den Behälter vom Typ A
                  (daher der Name accumulator)

BinaryOperator<A> bringt alle Elemente aus einem temporären Behälter (2-ter Parameter) vom Typ A
                  in den vom Supplier bereitgestellten Behälter vom Typ A (1-ter Parameter)
                  (daher der Name combiner)
                  Der combiner wird nur im parallelen Fall verwendet, was man durch eine Konsolmeldung zeigen kann.

Function<A,R>     erhält den vom Supplier bereitgestellten Behälter und bringt die Elemente
                  in einen Behälter vom Typ R und gibt diesen Behälter zurück.

Beispiel: Einen Stream in einer unveränderbare Liste bringen
//Supplier<A> supplier  A = List<String>
Supplier<List<String>> supplier = ArrayList::new;
// BiConsumer<A,T> accumulator   T = String
BiConsumer<List<String>,String> accumulator = List::add ; // (list, s) -> list.add(s);
//BinaryOperator<A> combiner
BinaryOperator<List<String>> combiner = (left, right) -> { left.addAll(right); return left; };
// Im nichtparallelen Fall kann der combiner einfach null zurückgeben, er darf aber selbst nicht null sein.
// Function<A,R> finisher    R = List<String>
Function<List<String>,List<String>> finisher = Collections::unmodifiableList;
//  Collector<T,A,R>
Collector<String,List<String>,List<String>>  myCollector = Collector.of(supplier,
                                                                         accumulator,
                                                                         combiner,
                                                                         finisher);

Stream<String> stringStream = Stream.of("Doris", "Diana", "Berta", "Bruno", "Bernd", "Beate", "Anna", "Anke");
List<String> immutableList = stringStream.collect(myCollector);
System.out.println(immutableList);
//immutableList.add("ccc"); // java.lang.UnsupportedOperationException

Ausgabe

[Doris, Diana, Berta, Bruno, Bernd, Beate, Anna, Anke]

Die 3 + 1 Methode (3 obligatorische Parameter + 1 optionaler Parameter)

Die Methode hat die folgende Form

static <T,R,R> Collector<T,R,R> of(Supplier<R>       supplier,
                                   BiConsumer<R,T>   accumulator,
                                   BinaryOperator<R> combiner,
                                   Collector.Characteristics... characteristics)

Die Bedeutung der Parameter

Supplier<R>       liefert einen Behälter vom Typ R, der Elemente vom Typ T aufnehmen kann

BiConsumer<R,T>   bringt Elemente vom Typ T in den Behälter vom Typ R
                  (daher der Name accumulator)

BinaryOperator<R> bringt alle Elemente aus einem temporären Behälter (2-ter Parameter) vom Typ R
                  in den vom Supplier bereitgestellten Behälter vom Typ R (1-ter Parameter)
                  (daher der Name combiner)
                  Der combiner wird nur im parallelen Fall verwendet, was man durch eine Konsolmeldung zeigen kann.

Diese Methode entspricht im Wesentlichen der zweiten collect()-Methode aus Stream<T>, allerdings mit einem wichtigen Unterschied: Der dritte Parameter ist hier ein BiConsumer<R,R> und kein BinaryOperator<R>

<R> R  collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)

Beispiel: Einen Stream in eine TreeSet bringen
Stream<String> stringStream2 = Stream.of("Doris", "Diana", "Berta", "Bruno", "Bernd", "Beate", "Anna", "Anke");
BiConsumer<Set<String>,String> setAccumulator = (set, st) -> { if(st.startsWith("B")) set.add(st); } ;
BinaryOperator<Set<String>> setCombiner = (left, right) -> { System.out.println("comb*");left.addAll(right); return left; };
//Function<Set<String>,Set<String>> setFinisher = Collections::unmodifiableSet;

Collector<String,Set<String>,Set<String>>  setCollector = Collector.of( TreeSet::new,
                                                                        setAccumulator,
                                                                        setCombiner);
                                                                        //setFinisher);
Set<String> treeSet = stringStream2.collect(setCollector);
System.out.println(treeSet);

Ausgabe

[Beate, Bernd, Berta, Bruno]

Beispiel: Einen Stream in eine TreeSet bringen [mit collect()-Methode aus Stream<T>]

Wenn wir die zweite collect()-Methode aus Stream<T> verwenden wollen müssen wir aus dem BinaryOperator<R> einen BiConsumer<R,R> machen. Hierzu wird einfach das return-Statement weggelassen.

// wie vorher
BiConsumer<Set<String>,String> setAccumulator = (set, st) -> { if(st.startsWith("B")) set.add(st); } ;

// hier jetzt BiConsumer<Set<String>,Set<String>> und kein BinaryOperator<Set<String>>
BiConsumer<Set<String>,Set<String>> consCombiner = (left, right) -> { System.out.println("comb+");left.addAll(right); };

Stream<String> stringStream = Stream.of("Doris", "Diana", "Berta", "Bruno", "Bernd", "Beate", "Anna", "Anke");
Set<String> treeSet3 = stringStream.parallel().collect(TreeSet::new,
                                                       setAccumulator,
                                                       consCombiner);
System.out.println(treeSet3);

Valid XHTML 1.0 Strict top Back Next Up Home