New features of JDK 1.8 -- Collector interface and Collector tool class

Keywords: Java JDK SQL

Absrtact: This article mainly studied the Collector interface and Collector utility classes newly added in Java 1.8, and the improvement and optimization of using them in collection processing.

Some of the content comes from the following Blogs:

https://www.jianshu.com/p/7eaa0969b424

Streaming processing

The new streaming processing in JDK 1.8 provides an efficient and easy-to-use way to process data. It can perform very complex operations such as searching, filtering and mapping data on the collection, greatly simplifying the use of the collection. With streaming, you can operate on a collection just as you would with SQL statements.

JDK 1.8 implements the processing of convection through internal iteration. A flow processing can be divided into three parts: conversion to flow, intermediate operation and termination operation.

Conversion into flow

For collections, you can use the stream() method or the parallelStream() method in the collection class to convert the collection to a stream.

Intermediate operation

Intermediate operations can process the flow and return the processed flow object. Multiple intermediate operations can be connected to form a pipeline until the execution of the termination operation ends the execution of the flow.

Termination operation

The terminate operation will process the flow after the intermediate operation and return any data that is not a flow.

Collector interface

In the termination operation of convection, one method is collect, which collects elements and processes them, and finally returns the processed non flow objects.

See the method definition as follows:

1 <R, A> R collect(Collector<? super T, A, R> collector);

As you can see, the collect method requires an instance object of the Collector interface to be passed in. The Collector can be seen as a tool for processing streams. Many Collector tools are encapsulated in the Collectors.

global variable

Collector mainly contains five parameters, and its behavior is also defined by these five parameters, as follows:

 1 // supplier Parameter is used to generate a result container of type A. 
 2 Supplier<A> supplier();
 3 // accumulator For inductive elements, generics T Is the element, which will match the elements in the flow with the result container A An operation occurred.
 4 BiConsumer<A, T> accumulator();
 5 // combiner Used to merge the results of two parallel executions into the final result A. 
 6 BinaryOperator<A> combiner();
 7 // finisher Used to complete previous results R Turn to A. 
 8 Function<A, R> finisher();
 9 // characteristics Present Collector Is an immutable Set. 
10 Set<Characteristics> characteristics();

enumeration

Characteristics this characteristic value is an enumeration:

1 enum Characteristics {
2     // Multithreading.
3     CONCURRENT,
4     // Disorder.
5     UNORDERED,
6     // No conversion is required.
7     IDENTITY_FINISH
8 }

Construction method

Collector has two of methods for generating collector instances, one of which has all five parameters above and the other four, excluding the finisher parameter.

 1 // Four parameter method for generating a Collector,T Represents the elements in the flow, R Represents the final result. Because no finisher Parameter, so you need to have IDENTITY_FINISH Eigenvalues.
 2 public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
 3                                           BiConsumer<R, T> accumulator,
 4                                           BinaryOperator<R> combiner,
 5                                           Characteristics... characteristics) {
 6     Objects.requireNonNull(supplier);
 7     Objects.requireNonNull(accumulator);
 8     Objects.requireNonNull(combiner);
 9     Objects.requireNonNull(characteristics);
10     Set<Characteristics> cs = (characteristics.length == 0)
11                               ? Collectors.CH_ID
12                               : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
13                                                                        characteristics));
14     return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
15 }
16 
17 // Five parameter method, used to generate a Collector,T Represents the elements in the flow, A For intermediate results, R Represents the final result, finisher Will be used A Convert to R. 
18 public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
19                                              BiConsumer<A, T> accumulator,
20                                              BinaryOperator<A> combiner,
21                                              Function<A, R> finisher,
22                                              Characteristics... characteristics) {
23     Objects.requireNonNull(supplier);
24     Objects.requireNonNull(accumulator);
25     Objects.requireNonNull(combiner);
26     Objects.requireNonNull(finisher);
27     Objects.requireNonNull(characteristics);
28     Set<Characteristics> cs = Collectors.CH_NOID;
29     if (characteristics.length > 0) {
30         cs = EnumSet.noneOf(Characteristics.class);
31         Collections.addAll(cs, characteristics);
32         cs = Collections.unmodifiableSet(cs);
33     }
34     return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
35 }

Collectors utility class

Collector s is a tool class that JDK pre implements Collectors. It provides a variety of Collectors internally.

toCollection method

Put all the elements in the stream into a Collection to return. Here, Collection is used, which generally refers to multiple collections.

Method:

1 public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
2     return new CollectorImpl<>(
3             collectionFactory, Collection<T>::add,
4             (r1, r2) -> { r1.addAll(r2); return r1; }, 
5             CH_ID);
6 }

Example:

1 public static void main(String[] args) {
2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
4     LinkedList<String> newList = list.stream().collect(Collectors.toCollection(LinkedList::new));
5     System.out.println(newList);// [123, 521, 100, 228, 838, 250, 345]
6 }

toList method

Put the elements in the flow into a List collection and return it. The default is ArrayList.

Method:

1 public static <T>
2 Collector<T, ?, List<T>> toList() {
3     return new CollectorImpl<>(
4             (Supplier<List<T>>) ArrayList::new, List::add,
5             (left, right) -> { left.addAll(right); return left; },
6             CH_ID);
7 }

Example:

1 public static void main(String[] args) {
2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
4     List<String> newList = list.stream().collect(Collectors.toList());
5     System.out.println(newList);// [123, 521, 100, 228, 838, 250, 345]
6 }

toSet method

Put the elements in the flow into a Set collection and return, the default is HashSet.

Method:

1 public static <T> Collector<T, ?, Set<T>> toSet() {
2     return new CollectorImpl<>(
3             (Supplier<Set<T>>) HashSet::new, Set::add,
4             (left, right) -> { left.addAll(right); return left; },
5             CH_UNORDERED_ID);
6 }

Example:

1 public static void main(String[] args) {
2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
4     Set<String> newSet = list.stream().collect(Collectors.toSet());
5     System.out.println(newSet);// [100, 123, 521, 345, 228, 838, 250]
6 }

toMap method

According to the incoming key generator and value generator, save the generated key and value to a Map for return. The generation of key and value depends on the element. You can specify the processing scheme when duplicate key occurs and the Map to save the result.

There are also three overload methods that support concurrent tocurrentmap. They are basically the same as toMap, except that the last Map it uses is concurrent concurrent HashMap.

Method:

 1 // Specifies the generation method of key and value. In case of key conflict, an exception will be thrown by default, which is used by default HashMap. 
 2 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
 3             Function<? super T, ? extends K> keyMapper,
 4             Function<? super T, ? extends U> valueMapper) {
 5     return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
 6 }
 7 // Specifies the generation method of key and value. In case of key conflict, the method passed in is used for processing. The default method is HashMap. 
 8 public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
 9             Function<? super T, ? extends K> keyMapper,
10             Function<? super T, ? extends U> valueMapper,
11             BinaryOperator<U> mergeFunction) {
12     return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
13 }
14 // Specify the generation method of key and value. In case of key conflict, use the passed in method to handle, and use the passed in method to Map Type returns data. The first two methods finally call this method to return Map Data.
15 public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(
16             Function<? super T, ? extends K> keyMapper,
17             Function<? super T, ? extends U> valueMapper,
18             BinaryOperator<U> mergeFunction,
19             Supplier<M> mapSupplier) {
20     BiConsumer<M, T> accumulator = (map, element) -> map.merge(
21             keyMapper.apply(element), 
22             valueMapper.apply(element), 
23             mergeFunction);
24     return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
25 }

Example:

 1 public static void main(String[] args) {
 2     Map<String, String> newMap = null;
 3     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
 4     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
 5     // 123 The keys of and 100 are both 1, causing conflicts. By default, an exception is thrown. Use the limit Intercepts the first two elements.
 6     newMap = list.stream().limit(2).collect(Collectors.toMap(e -> e.substring(0, 1), e -> e));
 7     System.out.println(newMap);// {1=123, 5=521}
 8     // The processing method when the primary key conflict is passed in. The value inserted first is reserved. It is used by default HashMap,Sort the primary key from small to large.
 9     newMap = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (m, n) -> m));
10     System.out.println(newMap);// {1=123, 2=228, 3=345, 5=521, 8=838}
11     // The processing method when the primary key conflict is passed in. The newly inserted value is retained. The default is LinkedHashMap,Sort the primary keys in the order they are inserted.
12     newMap = list.stream().collect(Collectors.toMap(e -> e.substring(0, 1), e -> e, (m, n) -> n, LinkedHashMap::new));
13     System.out.println(newMap);// {1=100, 5=521, 2=250, 8=838, 3=345}
14 }

joining method

Connect all the elements in the stream as strings. You can specify connectors or prefixes.

Method:

 1 // Connect all the elements in the stream as strings without using connectors or specifying prefixes or suffixes.
 2 public static Collector<CharSequence, ?, String> joining() {
 3     return new CollectorImpl<CharSequence, StringBuilder, String>(
 4             StringBuilder::new, StringBuilder::append,
 5             (r1, r2) -> { r1.append(r2); return r1; },
 6             StringBuilder::toString, CH_NOID);
 7 }
 8 // Connect all elements in the stream as strings, using the specified connector, without specifying the prefix or suffix.
 9 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
10     return joining(delimiter, "", "");
11 }
12 // Connect all the elements in the stream as strings, using the specified connector and the specified prefix and suffix.
13 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
14                                                          CharSequence prefix,
15                                                          CharSequence suffix) {
16     return new CollectorImpl<>(
17             () -> new StringJoiner(delimiter, prefix, suffix),
18             StringJoiner::add, StringJoiner::merge,
19             StringJoiner::toString, CH_NOID);
20 }

Example:

 1 public static void main(String[] args) {
 2     String str = null;
 3     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
 4     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
 5     str = list.stream().collect(Collectors.joining());
 6     System.out.println(str);// 123521100228838250345
 7     str = list.stream().collect(Collectors.joining("-"));
 8     System.out.println(str);// 123-521-100-228-838-250-345
 9     str = list.stream().collect(Collectors.joining("-", "<", ">"));
10     System.out.println(str);// <123-521-100-228-838-250-345>
11 }

mapping method

Process the elements in the flow according to the method passed in, and return the result in the specified format.

Method:

 1 public static <T, U, A, R>
 2 Collector<T, ?, R> mapping(
 3             Function<? super T, ? extends U> mapper,
 4             Collector<? super U, A, R> downstream) {
 5     BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
 6     return new CollectorImpl<>(
 7             downstream.supplier(),
 8             (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
 9             downstream.combiner(),
10             downstream.finisher(),
11             downstream.characteristics());
12 }

Example:

1 public static void main(String[] args) {
2     List<Score> scoreList = new ArrayList<Score>();
3     scoreList.add(new Score("2019", "10", "Zhang San", 1));
4     scoreList.add(new Score("2019", "11", "Li Si", 1));
5     scoreList.add(new Score("2019", "12", "Wang Wu", 1));
6     List<String> names = scoreList.stream().collect(Collectors.mapping(Score::getName, Collectors.toList()));
7     System.out.println(names);// [Zhang San, Li Si, Wang Wu]
8 }

collectingAndThen method

This method reprocesses the result of induction after processing the incoming collector.

Method:

 1 public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(
 2             Collector<T,A,R> downstream,
 3             Function<R,RR> finisher) {
 4     Set<Collector.Characteristics> characteristics = downstream.characteristics();
 5     if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
 6         if (characteristics.size() == 1)
 7             characteristics = Collectors.CH_NOID;
 8         else {
 9             characteristics = EnumSet.copyOf(characteristics);
10             characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
11             characteristics = Collections.unmodifiableSet(characteristics);
12         }
13     }
14     return new CollectorImpl<>(downstream.supplier(),
15                                downstream.accumulator(),
16                                downstream.combiner(),
17                                downstream.finisher().andThen(finisher),
18                                characteristics);
19 }

Example:

1 public static void main(String[] args) {
2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
4     Integer size = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size));
5     System.out.println(size);// 7
6 }

counting method

This method is mainly used for counting.

Method:

1 public static <T> Collector<T, ?, Long> counting() {
2     return reducing(0L, e -> 1L, Long::sum);
3 }

Example:

1 public static void main(String[] args) {
2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
4     Long count = list.stream().collect(Collectors.counting());
5     System.out.println(count);// 7
6 }

reducing method

There are three overloaded methods for statistical induction of elements in the Stream, which correspond to the three reduce methods in the Stream. They can be replaced and used, with the same effect.

Method:

 1 // Return one that can be generated directly Optional Type result Collector,There is no initial value.
 2 public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {
 3     class OptionalBox implements Consumer<T> {
 4         T value = null;
 5         boolean present = false;
 6 
 7         @Override
 8         public void accept(T t) {
 9             if (present) {
10                 value = op.apply(value, t);
11             }
12             else {
13                 value = t;
14                 present = true;
15             }
16         }
17     }
18     return new CollectorImpl<T, OptionalBox, Optional<T>>(
19             OptionalBox::new, OptionalBox::accept,
20             (a, b) -> { if (b.present) a.accept(b.value); return a; },
21             a -> Optional.ofNullable(a.value), CH_NOID);
22 }
23 // Returns a Collector,Specifies the initial value.
24 public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {
25     return new CollectorImpl<>(
26             boxSupplier(identity),
27             (a, t) -> { a[0] = op.apply(a[0], t); },
28             (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
29             a -> a[0],
30             CH_NOID);
31 }
32 // Returns a Collector,Specifies the initial value to convert the flow using the incoming method before returning the result.
33 public static <T, U> Collector<T, ?, U> reducing(
34             U identity,
35             Function<? super T, ? extends U> mapper,
36             BinaryOperator<U> op) {
37     return new CollectorImpl<>(
38             boxSupplier(identity),
39             (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
40             (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
41             a -> a[0], CH_NOID);
42 }

Example:

 1 public static void main(String[] args) {
 2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
 3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
 4     Optional<Integer> optional = list.stream().limit(4).map(String::length).collect(Collectors.reducing(Integer::sum));
 5     System.out.println(optional);// Optional[12]
 6     Integer integer = list.stream().limit(3).map(String::length).collect(Collectors.reducing(0, Integer::sum));
 7     System.out.println(integer);// 9
 8     Integer sum = list.stream().limit(4).collect(Collectors.reducing(0, String::length, Integer::sum));
 9     System.out.println(sum);// 12
10 }

minBy method and maxBy method

Generate a Collector to get the minimum or maximum Optional results.

Method:

1 public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) {
2     return reducing(BinaryOperator.minBy(comparator));
3 }
4 public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) {
5     return reducing(BinaryOperator.maxBy(comparator));
6 }

Example:

1 public static void main(String[] args) {
2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
4     Optional<String> max = list.stream().collect(Collectors.maxBy((m, n) -> Integer.valueOf(m) - Integer.valueOf(n)));
5     System.out.println(max);// Optional[838]
6     Optional<String> min = list.stream().collect(Collectors.minBy((m, n) -> Integer.valueOf(m) - Integer.valueOf(n)));
7     System.out.println(min);// Optional[100]
8 }

summingInt method, summingLong method and summingDouble method

Generate a Collector to sum the elements, first convert the elements to type, and then sum them.

The function of the parameter is to convert the element to the specified type, and the final result is the same as the converted type.

Method:

 1 public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) {
 2     return new CollectorImpl<>(
 3             () -> new int[1],
 4             (a, t) -> { a[0] += mapper.applyAsInt(t); },
 5             (a, b) -> { a[0] += b[0]; return a; },
 6             a -> a[0], CH_NOID);
 7 }
 8 public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) {
 9     return new CollectorImpl<>(
10             () -> new long[1],
11             (a, t) -> { a[0] += mapper.applyAsLong(t); },
12             (a, b) -> { a[0] += b[0]; return a; },
13             a -> a[0], CH_NOID);
14 }
15 public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) {
16     return new CollectorImpl<>(
17             () -> new double[3],
18             (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
19                         a[2] += mapper.applyAsDouble(t); },
20             (a, b) -> { sumWithCompensation(a, b[0]);
21                         a[2] += b[2]; return sumWithCompensation(a, b[1]); },
22             a -> computeFinalSum(a), CH_NOID);
23 }

Example:

 1 public static void main(String[] args) {
 2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
 3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
 4     Integer intCollect = list.stream().collect(Collectors.summingInt(Integer::parseInt));
 5     System.out.println(intCollect);// 2405
 6     Long longCollect = list.stream().collect(Collectors.summingLong(Long::parseLong));
 7     System.out.println(longCollect);// 2405
 8     Double doubleCollect = list.stream().collect(Collectors.summingDouble(Double::parseDouble));
 9     System.out.println(doubleCollect);// 2405.0
10 }

summarizingInt method, summarizingLong method and summarizingDouble method

These three methods are applicable to summary, and the return values are IntSummaryStatistics, LongSummaryStatistics and DoubleSummaryStatistics.

These return values contain the number, sum, maximum, minimum, and average of the specified results for the elements in the flow.

Method:

 1 public static <T> Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
 2     return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
 3             IntSummaryStatistics::new,
 4             (r, t) -> r.accept(mapper.applyAsInt(t)),
 5             (l, r) -> { l.combine(r); return l; }, CH_ID);
 6 }
 7 public static <T> Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {
 8     return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>(
 9             LongSummaryStatistics::new,
10             (r, t) -> r.accept(mapper.applyAsLong(t)),
11             (l, r) -> { l.combine(r); return l; }, CH_ID);
12 }
13 public static <T> Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {
14     return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>(
15             DoubleSummaryStatistics::new,
16             (r, t) -> r.accept(mapper.applyAsDouble(t)),
17             (l, r) -> { l.combine(r); return l; }, CH_ID);
18 }

Example:

 1 public static void main(String[] args) {
 2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
 3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
 4     IntSummaryStatistics intSummaryStatistics = list.stream().collect(Collectors.summarizingInt(Integer::parseInt));
 5     System.out.println(intSummaryStatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838}
 6     LongSummaryStatistics longSummaryStatistics = list.stream().collect(Collectors.summarizingLong(Long::parseLong));
 7     System.out.println(longSummaryStatistics);// {count=7, sum=2405, min=100, average=343.571429, max=838}
 8     DoubleSummaryStatistics doubleSummaryStatistics = list.stream().collect(Collectors.summarizingDouble(Double::parseDouble));
 9     System.out.println(doubleSummaryStatistics);// {count=7, sum=2405.000000, min=100.000000, average=343.571429, max=838.000000}
10 }

averagingInt method, averagingLong method and averagingDouble method

Generate a Collector to average the elements, first convert the elements to type, and then average them.

The function of the parameter is to convert the element to the specified type. Averaging involves division, and the result is always of Double type.

Method:

 1 public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) {
 2     return new CollectorImpl<>(
 3             () -> new long[2],
 4             (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
 5             (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
 6             a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
 7 }
 8 public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) {
 9     return new CollectorImpl<>(
10             () -> new long[2],
11             (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
12             (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
13             a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
14 }
15 public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) {
16     return new CollectorImpl<>(
17             () -> new double[4],
18             (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t); },
19             (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
20             a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), CH_NOID);
21 }

Example:

 1 public static void main(String[] args) {
 2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
 3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
 4     double intAverage = list.stream().collect(Collectors.averagingInt(Integer::parseInt));
 5     System.out.println(intAverage);// 343.57142857142856
 6     double longAverage = list.stream().collect(Collectors.averagingLong(Long::parseLong));
 7     System.out.println(longAverage);// 343.57142857142856
 8     double doubleAverage = list.stream().collect(Collectors.averagingDouble(Double::parseDouble));
 9     System.out.println(doubleAverage);// 343.57142857142856
10 }

groupingBy method

There are three overloaded methods to generate a Collector with grouping function.

Method:

 1 // Only one grouping parameter is required classifier,Automatically save results to a Map In each Map The type of key is classifier The result type of. By default, the elements of the group are saved in the List Medium.
 2 public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(
 3             Function<? super T, ? extends K> classifier) {
 4     return groupingBy(classifier, toList());
 5 }
 6 // On the basis of the above method, the processing method of elements in convection is added Collector,The default is List. 
 7 public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(
 8             Function<? super T, ? extends K> classifier,
 9             Collector<? super T, A, D> downstream) {
10     return groupingBy(classifier, HashMap::new, downstream);
11 }
12 // Add the result based on the second method Map The default is HashMap. 
13 public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(
14             Function<? super T, ? extends K> classifier,
15             Supplier<M> mapFactory,
16             Collector<? super T, A, D> downstream) {
17     Supplier<A> downstreamSupplier = downstream.supplier();
18     BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
19     BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
20         K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
21         A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
22         downstreamAccumulator.accept(container, t);
23     };
24     BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
25     @SuppressWarnings("unchecked")
26     Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
27 
28     if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
29         return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
30     }
31     else {
32         @SuppressWarnings("unchecked")
33         Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
34         Function<Map<K, A>, M> finisher = intermediate -> {
35             intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
36             @SuppressWarnings("unchecked")
37             M castResult = (M) intermediate;
38             return castResult;
39         };
40         return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
41     }
42 }

Example:

 1 public static void main(String[] args) {
 2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
 3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
 4     Map<String, List<String>> groupByFirst = list.stream().collect(Collectors.groupingBy(e -> e.substring(0, 1)));
 5     System.out.println(groupByFirst);// {1=[123, 100], 2=[228, 250], 3=[345], 5=[521], 8=[838]}
 6     Map<String, Set<String>> groupByLast = list.stream().collect(Collectors.groupingBy(e -> e.substring(e.length() - 1), Collectors.toSet()));
 7     System.out.println(groupByLast);// {0=[100, 250], 1=[521], 3=[123], 5=[345], 8=[228, 838]}
 8     Map<Integer, Set<String>> groupByLength = list.stream().collect(Collectors.groupingBy(String::length, HashMap::new, Collectors.toSet()));
 9     System.out.println(groupByLength);// {3=[100, 123, 521, 345, 228, 838, 250]}
10 }

partitioningBy method

The elements in the flow are divided into two parts according to the results of the given validation rules, which are returned in the Map. The key is of Boolean type and the value is the List of elements.

Method:

 1 // Only one verification parameter is required predicate. 
 2 public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
 3     return partitioningBy(predicate, toList());
 4 }
 5 // On the basis of the above method, the processing method of elements in convection is added Collector,The default approach is Collectors.toList(). 
 6 public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
 7                                                 Collector<? super T, A, D> downstream) {
 8     BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
 9     BiConsumer<Partition<A>, T> accumulator = (result, t) ->
10             downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
11     BinaryOperator<A> op = downstream.combiner();
12     BinaryOperator<Partition<A>> merger = (left, right) ->
13             new Partition<>(op.apply(left.forTrue, right.forTrue),
14                             op.apply(left.forFalse, right.forFalse));
15     Supplier<Partition<A>> supplier = () ->
16             new Partition<>(downstream.supplier().get(),
17                             downstream.supplier().get());
18     if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
19         return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
20     }
21     else {
22         Function<Partition<A>, Map<Boolean, D>> finisher = par ->
23                 new Partition<>(downstream.finisher().apply(par.forTrue),
24                                 downstream.finisher().apply(par.forFalse));
25         return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
26     }
27 }

Example:

1 public static void main(String[] args) {
2     List<String> list = Arrays.asList("123", "521", "100", "228", "838", "250", "345");
3     System.out.println(list);// [123, 521, 100, 228, 838, 250, 345]
4     Map<Boolean, List<String>> moreThan = list.stream().collect(Collectors.partitioningBy(e -> Integer.parseInt(e) > 300));
5     System.out.println(moreThan);// {false=[123, 100, 228, 250], true=[521, 838, 345]}
6     Map<Boolean, Set<String>> lessThan = list.stream().collect(Collectors.partitioningBy(e -> Integer.parseInt(e) < 300, Collectors.toSet()));
7     System.out.println(lessThan);// {false=[521, 345, 838], true=[100, 123, 228, 250]}
8 }

Posted by MikeDXUNL on Sat, 09 Nov 2019 10:11:14 -0800