This topic is about collect() terminal operation and the predefined Collectors.
group/partition |
The collect() method is an advanced reduction, it is more efficient than a regular reduction. While regular reduce() combines two values and get a new accumulated object each fold, collect() use the same mutable object for accumulating.
The method signature are as follows:
- <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
- <R, A> R collect(Collector<? super T, A, R> collector)
The first signature is general purpose. The first parameter is a Supplier that creates the mutable object that will store the accumulating results. The second parameter is a BiConsumer, which is used to add one more element to that mutable accumulating object. The third parameter is another BiConsume. It is responsible for taking two mutable accumulating objects and merging them into one. The is useful when we collect with parallel stream. The following example collect a stream of String into a StringBuilder and ArrayList<String> respectively.
StringBuilder greeting = Stream.of("hello", "world", "!").collect(StringBuilder::new, StringBuilder:append, StringBuilder::append);
ArrayList<String> greeting2 = Stream.of("hello", "world", "!").collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
The second signature accepts predefined collectors which implement Collector interface.
Unfortunately, we need to remember almost all of the predefined Collectors for OCPJP, so start to read the javadoc, then take a look at the following long list of examples:
Collectors that reduce the Stream into a number or String
averagingxxx, counting, joining, maxBy, minBy, reducing, sumarizingxxx, summingxxx.
OCPJP>cat CommonCollectorsDemo.java
import java.util.ArrayList;
import java.util.DoubleSummaryStatistics;
import java.util.IntSummaryStatistics;
import java.util.LongSummaryStatistics;
import java.util.List;
import java.util.Optional;
import java.util.stream.*;
public class CommonCollectorsDemo {
public static void main(String[] args) {
System.out.println("static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) ");
Stream<String> stream = Stream.of("cat", "Apple", "John", "something");
double average = stream.collect(Collectors.averagingDouble(String::length));
System.out.println("Collectors.averagingDouble: " + average);
System.out.println("static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) ");
average = Stream.of("cat", "Apple", "John", "something").collect(Collectors.averagingInt(String::length));
System.out.println("Collectors.averagingInt: " + average);
System.out.println("static <T> Collector<T, ?, Long> averagingLong(ToLongFunction<? super T> mapper) ");
average = Stream.of("cat", "Apple", "John", "something").collect(Collectors.averagingLong(String::length));
System.out.println("Collectors.averagingLong: " + average);
List<String> list = new ArrayList<>();
list.add("car");
list.add("ship");
list.add("airplane");
System.out.println("static <T> Collector<T, ?, Long> counting() ");
Long counting = list.stream().collect(Collectors.counting());
System.out.println("Collectors.counting: " + counting);
System.out.println("static Collecor<CharSequence, ?, String> joining() ");
String joining = list.stream().collect(Collectors.joining());
System.out.println("Collectors.joining: " + joining);
System.out.println("static Collector<CharSequence, ?, String> joining(CharSequence delimiter) ");
joining = list.stream().collect(Collectors.joining(", "));
System.out.println("Collectors.joining(\", \"): " + joining);
System.out.println("static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) ");
Optional<String> maxBy = list.stream().collect(Collectors.maxBy(String::compareToIgnoreCase));
maxBy.ifPresent(i -> System.out.println("Collectors.maxBy: " + maxBy.get()));
System.out.println("static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) ");
Optional<String> minBy = list.stream().collect(Collectors.minBy(String::compareToIgnoreCase));
minBy.ifPresent(i -> System.out.println("Collectors.minBy: " + minBy.get()));
System.out.println("static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) ");
Optional<String> reducing = list.stream().collect(Collectors.reducing(String::concat));
reducing.ifPresent(i -> System.out.println("Collectors.reducing: " + reducing.get()));
System.out.println("static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) ");
DoubleSummaryStatistics summarizingDouble = list.stream().collect(Collectors.summarizingDouble(String::length));
System.out.println("Collectors.summarizingDouble: getAverage = " + summarizingDouble.getAverage()
+ " getCount=" + summarizingDouble.getCount()
+ " getMax=" + summarizingDouble.getMax()
+ " getMin=" + summarizingDouble.getMin()
+ " getSum=" + summarizingDouble.getSum());
System.out.println("static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) ");
IntSummaryStatistics summarizingInt = list.stream().collect(Collectors.summarizingInt(String::length));
System.out.println("Collectors.summarizingInt: getAverage = " + summarizingInt.getAverage()
+ " getCount = " + summarizingInt.getCount()
+ " getMax = " + summarizingInt.getMax()
+ " getMin = " + summarizingInt.getMin()
+ " getSum = " + summarizingInt.getSum());
System.out.println("static <T> Collector<T, ?, LongSummaryStaticstics> summarizingLong(ToLongFunction<? super T> mapper) ");
LongSummaryStatistics summarizingLong = list.stream().collect(Collectors.summarizingLong(String::length));
System.out.println("Collectors.summarizingLong: getAverage = " + summarizingLong.getAverage()
+ " getCount = " + summarizingLong.getAverage()
+ " getMax = " + summarizingLong.getMax()
+ " getMin = " + summarizingLong.getMin()
+ " getSum = " + summarizingLong.getSum());
System.out.println("static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) ");
double summingDouble = list.stream().collect(Collectors.summingDouble(String::length));
System.out.println("Collectors.summingDouble: " + summingDouble);
System.out.println("static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) ");
int summingInt = list.stream().collect(Collectors.summingInt(String::length));
System.out.println("Collectors.summingInt: " + summingInt);
System.out.println("static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) ");
long summingLong = list.stream().collect(Collectors.summingLong(String::length));
System.out.println("Collectors.summingLong: " + summingLong);
}
}
OCPJP>
OCPJP>
OCPJP>javac CommonCollectorsDemo.java
OCPJP>java CommonCollectorsDemo
static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper)
Collectors.averagingDouble: 5.25
static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper)
Collectors.averagingInt: 5.25
static <T> Collector<T, ?, Long> averagingLong(ToLongFunction<? super T> mapper)
Collectors.averagingLong: 5.25
static <T> Collector<T, ?, Long> counting()
Collectors.counting: 3
static Collecor<CharSequence, ?, String> joining()
Collectors.joining: carshipairplane
static Collector<CharSequence, ?, String> joining(CharSequence delimiter)
Collectors.joining(", "): car, ship, airplane
static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator)
Collectors.maxBy: ship
static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator)
Collectors.minBy: airplane
static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op)
Collectors.reducing: carshipairplane
static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper)
Collectors.summarizingDouble: getAverage = 5.0 getCount=3 getMax=8.0 getMin=3.0 getSum=15.0
static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper)
Collectors.summarizingInt: getAverage = 5.0 getCount = 3 getMax = 8 getMin = 3 getSum = 15
static <T> Collector<T, ?, LongSummaryStaticstics> summarizingLong(ToLongFunction<? super T> mapper)
Collectors.summarizingLong: getAverage = 5.0 getCount = 5.0 getMax = 8 getMin = 3 getSum = 15
static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper)
Collectors.summingDouble: 15.0
static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper)
Collectors.summingInt: 15
static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper)
Collectors.summingLong: 15
OCPJP>
Collectors that reduce the Stream into a Collection
toCollection, toSet, toList
OCPJP>cat ToCollectionDemo.java
import java.util.stream.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ToCollectionDemo {
public static void main(String...args) {
Stream<String> stream = Arrays.asList("dog", "fish", "cat", "bird").stream();
System.out.println("static <T, C extends Collection<T>> collector<T, ? , C> toCollection(Supplier<C> collectionFactory) ");
Set<String> set = stream.collect(Collectors.toCollection(HashSet::new));
System.out.println("Collectors.toCollection: " + set);
stream = set.stream();
System.out.println("static <T> collector<T, ? List<T>> toList() ");
List<String> list = stream.collect(Collectors.toList());
System.out.println("Collectors.toList: " + list);
stream = list.stream();
System.out.println("static <T> collector<T, ?, Set<T>> toSet() ");
set = stream.collect(Collectors.toSet());
System.out.println("Collectors.toSet: " + set);
}
}
OCPJP>
OCPJP>
OCPJP>javac ToCollectionDemo.java
OCPJP>java ToCollectionDemo
static <T, C extends Collection<T>> collector<T, ? , C> toCollection(Supplier<C> collectionFactory)
Collectors.toCollection: [fish, cat, bird, dog]
static <T> collector<T, ? List<T>> toList()
Collectors.toList: [fish, cat, bird, dog]
static <T> collector<T, ?, Set<T>> toSet()
Collectors.toSet: [fish, cat, bird, dog]
OCPJP>
Collectors that reduce the Stream into a Map
toMap, groupBy, partitionBy, mapping
toMap() have 3 signatures, example usages are:
Map<String, String> wordToFirstSubString = Stream.of("hello", "world", "!").collect(Collectors.toMap(k -> k, v -> v.substring(0, 1))); //{hello=h, world=w, !=!}
Map<Integer, String> lengthToString = Stream.of("hello", "world", "!").collect(Collectors.toMap(String::length, v -> v, (s1, s2) -> s1 + "concat to " + s2)); //{5=hello concat to world, 1=!}
The groupingBy() collector tells collect() that it should group all of the elements of the stream into lists, classifying them by the function provided.
Map<Integer, List<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length)); //{5=[hello, world], 1=[!]}
Besides the one parameter signature, groupingBy() has 2 common signatures:
Map<Integer, Set<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length, Collectors.toSet()));
HashMap<Integer, Set<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length, HashMap::new, Collectors.toSet()));
Partitioning is a special css of grouping -- there are only two possible groups -- true and false.
Map<Integer, List<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.partitioningBy(s -> s.length() < 5)); //{false=[hello, world], true=[!]}
Finally, there is a mapping() collector that allow us to add another collector to deal with the each group collected with groupingBy().
Map<Integer, Optional<Character>> fun = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length, Collectors.mapping(s -> s.charAt(0), minBy(Comparator.naturalOrder())))); // {5=[h], 1=[!]}
toMap() have 3 signatures, example usages are:
- two parameter version: first lambda is key mapper, second lambda is value mapper.
Map<String, String> wordToFirstSubString = Stream.of("hello", "world", "!").collect(Collectors.toMap(k -> k, v -> v.substring(0, 1))); //{hello=h, world=w, !=!}
- three parameter version: the third parameter is a merger lambda used when a key have two values mapped to it.
Map<Integer, String> lengthToString = Stream.of("hello", "world", "!").collect(Collectors.toMap(String::length, v -> v, (s1, s2) -> s1 + "concat to " + s2)); //{5=hello concat to world, 1=!}
- four parameter version: the fourth parameter is a Supplier that specify how to construct the returned Map.
HashMap<Integer, String> lengthToString = Stream.of("hello", "world", "!").collect(Collectors.toMap(String::length, v -> v, (s1, s2) -> s1 + "concat to " + s2, HashMap::new)); //{5=hello concat to world, 1=!}
The groupingBy() collector tells collect() that it should group all of the elements of the stream into lists, classifying them by the function provided.
Map<Integer, List<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length)); //{5=[hello, world], 1=[!]}
Besides the one parameter signature, groupingBy() has 2 common signatures:
- group into other type other than List.
Map<Integer, Set<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length, Collectors.toSet()));
- specify Map's implementation class.
HashMap<Integer, Set<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length, HashMap::new, Collectors.toSet()));
Partitioning is a special css of grouping -- there are only two possible groups -- true and false.
Map<Integer, List<String>> wordsByLength = Stream.of("hello", "world", "!").collect(Collectors.partitioningBy(s -> s.length() < 5)); //{false=[hello, world], true=[!]}
Finally, there is a mapping() collector that allow us to add another collector to deal with the each group collected with groupingBy().
Map<Integer, Optional<Character>> fun = Stream.of("hello", "world", "!").collect(Collectors.groupingBy(String::length, Collectors.mapping(s -> s.charAt(0), minBy(Comparator.naturalOrder())))); // {5=[h], 1=[!]}
OCPJP>cat ToMapDemo.java
import java.util.stream.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.*;
import java.util.HashSet;
public class ToMapDemo {
public static void main(String[] args) {
System.out.println("static <T, K, U> Collector<T, ?, Map<K, U>> "
+ "toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) ");
Stream<Integer> stream = Stream.of(1, 2, 3);
Map<String, String> map = stream.collect(Collectors.toMap(i -> i + "key", i -> i + "value"));
System.out.println("Collectors.toMap: " + map);
System.out.println("static <T, K, U> Collector<T, ?, Map<K, U>> "
+ "toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, "
+ "BinaryOperator<U> mergeFunction)");
stream = Stream.of(1, 2, 3, 3);
//map = stream.collect(Collectors.toMap(i -> i + "key", i -> i + "value")); //java.lang.IllegalStateException: Duplicate key 3value
map = stream.collect(Collectors.toMap(i -> i + "key", i -> i + "value", (s1, s2) -> s1 + s2));
System.out.println("Collectors.toMap (with dup keys): " + map);
System.out.println("static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> "
+ "toMap(Function<? super T, ? extends K> keyMapper, "
+ "Function<? super T, ? extends U> valueMapper, "
+ "BinaryOperator<U> mergeFunction, "
+ "Supplier<M> mapSupplier)");
map = Stream.of(1, 2, 3, 3).collect(Collectors.toMap(i -> i + "key", i -> i + "value", (s1, s2) -> s1 + s2, TreeMap::new));
System.out.println("Collectors.toMap (with dup keys, want a specific Map): " + map);
System.out.println("static <T, K, U> Collector<T, ?, ConcurrentMap<K, U>> "
+ "toConcurrentMap(Function<? super T, ? extends K> keyMapper, "
+ "Function<? super T, ? extends U> valueMapper)");
stream = Stream.of(1, 2, 3);
map = stream.parallel().collect(Collectors.toConcurrentMap(i -> i + "key", i -> i + "value"));
System.out.println("Collectors.toConcurrentMap: " + map);
System.out.println("static <T, K, U> Collector<T, ?, ConcurrentMap<K, U>> "
+ "toConcurrentMap(Function<? super T, ? extends K> keyMapper, "
+ "Function<? super T, ? extends U> valueMapper, "
+ "BinaryOperator<U> mergeFunction)");
stream = Stream.of(1, 2, 3, 3);
map = stream.parallel().collect(Collectors.toConcurrentMap(i -> i + "key", i -> i + "value", String::concat));
System.out.println("Collectors.toConcurrentMap (with dup keys): " + map);
System.out.println("static <T, K, U, M extends ConcurrentMap<K, U>> Collector<T, ?, M> "
+ "toConcurrentMap(Function<? super T, ? extends K> keyMapper, "
+ "Function<? super T, ? extends U> valueMapper, "
+ "BinaryOperator<U> mergeFunction, "
+ "Supplier<M> mapSupplier)");
stream = Stream.of(1, 2, 3, 3);
map = stream.parallel().collect(Collectors.toConcurrentMap(i -> i + "key", i -> i + "value",
String::concat, ConcurrentHashMap::new));
System.out.println("Collectors.toConcurrentMap (dup keys, specified Map): " + map);
Set<String> set = new HashSet<>();
set.add("cat");
set.add("dog");
set.add("bird");
set.add("frog");
Stream<String> pets = set.stream();
System.out.println("static <T, K> Collector<T, ?, Map<K, List<T>>> "
+ "groupingBy(Function<? super T, ? extends K> classifier)");
Map<Integer, List<String>> map2 = pets.collect(Collectors.groupingBy(String::length));
System.out.println("Collectors.groupingBy: " + map2);
System.out.println("static <T, K, A, D> Collector<T, ?, Map<K, Map<T, D>>> "
+ "groupingBy(Function<? super T, ? extends K> classifier, "
+ "Collector<? super T, A, D> downStream)");
Map<Integer, Long> map3 = set.stream().collect(Collectors.groupingBy(String::length,
Collectors.counting()));
System.out.println("Collectors.groupingBy (Collectors for downStream): " + map3);
Map<Integer, Map<Integer, List<String>>> map4 = set.stream().collect(Collectors.groupingBy(String::length,
Collectors.groupingBy(String::length)));
System.out.println("Collectors.groupingBy (nested): " + map4);
System.out.println("static <T, K, A, D, M extends Map<K, D> Collector<T, ?, M> "
+ "groupingBy(Function<? super T, ? extends K> classifier, "
+ "Supplier<M> mapFactory, Collector<? super T, A, D> downStream)");
Map<Integer, Map<Integer, List<String>>> map5 = set.stream().collect(Collectors.groupingBy(String::length,
TreeMap::new, Collectors.groupingBy(String::length)));
System.out.println("Collectors.groupingBy (nested, specify map type)"
+ (map5 instanceof TreeMap) + " " + map5);
System.out.println("static <T> Collector<T, ?, Map<Boolean, List<T>>> "
+ "partitioningBy(Predicate<? super T> predicate)");
Map<Boolean, List<String>> map6 = set.stream().collect(Collectors.partitioningBy(i -> i.length() > 3));
System.out.println("Collectors.partitioningBy: " + map6);
System.out.println("static <T, D, A> Collector<T, ?, Map<Boolean, D>> "
+ "partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downStream)");
Map<Boolean, Map<Integer, List<String>>> map7 = set.stream().collect(Collectors
.partitioningBy(i -> i.length() > 3, Collectors.groupingBy(String::length)));
System.out.println("Collectors.partitioningBy (with downStream Collector): " + map7);
Map<Integer, List<String>> map8 = set.parallelStream().collect(Collectors.groupingByConcurrent(String::length));
System.out.println("Collectors.groupingByConcurrent: " + map8);
Map<Integer, String> map9 = set.parallelStream().collect(Collectors.groupingByConcurrent(
String::length, Collectors.joining()));
System.out.println("Collectors.groupingByConcurrent (with downStream Collector): " + map9);
Map<Integer, ConcurrentMap<Integer, List<String>>> map10 = set.parallelStream().collect(Collectors.groupingByConcurrent(
String::length, ConcurrentSkipListMap::new, Collectors.groupingByConcurrent(String::length)));
System.out.println("Collectors.groupingByConcurrent (with downStream Collector and specified ConcurrentMap tyep: "
+ (map10 instanceof ConcurrentSkipListMap) + map10);
System.out.println("static <T, U, A, R> Collector<T, ?, R> mapping("
+ "Function<? super T, ? super U> mapper, Collector<? super U, A, R> downStream)");
Set<String> mappedSet = set.stream().collect(Collectors.mapping(i -> i + i, Collectors.toSet()));
System.out.println("Collectors.mapping: " + mappedSet);
Map<Integer, Set<String>> map11 = set.stream().collect(Collectors.groupingBy(String::length,
Collectors.mapping(i -> i + i, Collectors.toSet())));
System.out.println("Collectors.mapping used with groupingBy: " + map11);
}
}
OCPJP>
OCPJP>
OCPJP>javac ToMapDemo.java
OCPJP>java ToMapDemo
static <T, K, U> Collector<T, ?, Map<K, U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)
Collectors.toMap: {3key=3value, 2key=2value, 1key=1value}
static <T, K, U> Collector<T, ?, Map<K, U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction)
Collectors.toMap (with dup keys): {3key=3value3value, 2key=2value, 1key=1value}
static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)
Collectors.toMap (with dup keys, want a specific Map): {1key=1value, 2key=2value, 3key=3value3value}
static <T, K, U> Collector<T, ?, ConcurrentMap<K, U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper)
Collectors.toConcurrentMap: {3key=3value, 2key=2value, 1key=1value}
static <T, K, U> Collector<T, ?, ConcurrentMap<K, U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction)
Collectors.toConcurrentMap (with dup keys): {3key=3value3value, 2key=2value, 1key=1value}
static <T, K, U, M extends ConcurrentMap<K, U>> Collector<T, ?, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier)
Collectors.toConcurrentMap (dup keys, specified Map): {3key=3value3value, 2key=2value, 1key=1value}
static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier)
Collectors.groupingBy: {3=[cat, dog], 4=[frog, bird]}
static <T, K, A, D> Collector<T, ?, Map<K, Map<T, D>>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downStream)
Collectors.groupingBy (Collectors for downStream): {3=2, 4=2}
Collectors.groupingBy (nested): {3={3=[cat, dog]}, 4={4=[frog, bird]}}
static <T, K, A, D, M extends Map<K, D> Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downStream)
Collectors.groupingBy (nested, specify map type)true {3={3=[cat, dog]}, 4={4=[frog, bird]}}
static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate)
Collectors.partitioningBy: {false=[cat, dog], true=[frog, bird]}
static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downStream)
Collectors.partitioningBy (with downStream Collector): {false={3=[cat, dog]}, true={4=[frog, bird]}}
Collectors.groupingByConcurrent: {3=[dog, cat], 4=[frog, bird]}
Collectors.groupingByConcurrent (with downStream Collector): {3=dogcat, 4=frogbird}
Collectors.groupingByConcurrent (with downStream Collector and specified ConcurrentMap tyep: true{3={3=[dog, cat]}, 4={4=[frog, bird]}}
static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? super U> mapper, Collector<? super U, A, R> downStream)
Collectors.mapping: [dogdog, frogfrog, birdbird, catcat]
Collectors.mapping used with groupingBy: {3=[dogdog, catcat], 4=[frogfrog, birdbird]}
OCPJP>
I print out the method signatures not because I want to drive you crazy, but because those are the definitive answer to any of your questions if your code refuse to compile.