Collectors class of Java 8 Stream

Static factory method of Collectors class

Factory method Return type effect
toList List<T> Collect all items in the stream into a List
toSet Set<T> Collect all items in the stream into a Set, delete duplicates
toCollection Collection<T> Collect all items in the stream into a collection created by a given supply sourcemenuStream.collect(toCollection(), ArrayList::new)
counting Long Count the number of elements in the stream
sumInt Integer Sum an integer attribute of items in the stream
averagingInt Double Calculate the average value of the Integer property of the items in the stream
summarizingInt IntSummaryStatistics Collect statistics about the Integer properties of items in the stream, such as maximum, minimum, sum, and average
joining String Connect the string generated by calling the toString method for each item in the streamcollect(joining(", "))
maxBy Optional<T> An Optional that wraps the largest element selected by the given comparator in the stream, or Optional.empty() if the stream is empty
my town Optional<T> An Optional that wraps the smallest element selected by the given comparator in the stream, or Optional.empty() if the stream is empty
reducing Types generated by the reduction operation Starting from an initial value as an accumulator, use BinaryOperator to combine with the elements in the stream one by one, thereby reducing the stream to a single value累加int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));
collectingAndThen The type returned by the conversion function Wrap another collector and apply a conversion function to its resultint howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size))
groupingBy Map<K, List<T>> Group the items in the stream according to the value of an attribute of the item, and use the attribute value as the key of the result Map
partitioningBy Map<Boolean,List<T>> Partition items based on the result of applying a predicate to each item in the stream

Collectors

There are all predefined implementations in the Collectors class. The general common practice is to use the following static imports to improve readability:

import static java.util.stream.Collectors.*;

 Or import the collectors of your choice individually:

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

All examples below will use the following demo data collection

List<String> givenList = Arrays.asList("a", "bb", "ccc", "dd");

Collectors.toList()

The ToList method can collect all the elements in the stream to the List instance. It should be noted that using this method cannot assume any specific implementation of List. If you want to specify a List implementation, you need to use toCollection instead. The following example creates a stream instance to represent a sequence of elements, and then collects it into the List instance object.

List<String> result = givenList.stream().collect(toList());

Collectors.toSet()

The ToSet method can collect all the elements in the stream to the Set instance. It should be noted that using this method cannot assume any specific implementation of Set. If you want to specify the Set implementation, you need to use toCollection instead. The following example creates a stream instance to represent the sequence of elements, Then collect it in the Set instance object

Set<String> result = givenList.stream().collect(toSet());

Set does not contain repeated elements. If there are duplicate elements in the set, only one is kept in the set:

List<String> listWithDuplicates = Arrays.asList("a", "bb", "c", "d", "bb");
Set<String> result = listWithDuplicates.stream().collect(toSet());
assertThat(result).hasSize(4);

Collectors.toCollection()

You may have noticed that with the toSet and toList collectors, you cannot specify its implementation. If you want to use a specific implementation, you need to use the toCollection collector and provide a specific collection implementation. The following example creates a stream instance to represent the sequence of elements, and then collects it in the LinkedList instance object

List<String> result = givenList.stream().collect(toCollection(LinkedList::new))

Note that immutable collections cannot be used here. Realize through custom Collector or use collectingAndThen.

Collectors.toMap()

The ToMap collector is used to collect stream elements to Map instances. Two functions are required to implement this function:

  • keyMapper
  • valueMapper

The keyMapper is used to extract the key of the map from the stream element, and the valueMapper extracts the value that can be associated.
The following example collects the stream elements into the Map, stores the string as the key, and its length as the value:

Map<String, Integer> result = givenList.stream()
  .collect(toMap(Function.identity(), String::length))

Function.identity() is a predefined shortcut function that returns the received parameters.
What if we have duplicate elements in our collection? Contrary to toSet, toMap cannot filter repeated elements. This is easier to understand-how to determine which value the key is associated with?

List<String> listWithDuplicates = Arrays.asList("a", "bb", "c", "d", "bb");
assertThatThrownBy(() -> {
    listWithDuplicates.stream().collect(toMap(Function.identity(), String::length));
}).isInstanceOf(IllegalStateException.class);

We see that toMap does not even judge whether the values ​​are equal, and if the key is repeated, an IllegalStateException is thrown immediately. When the key conflicts, we should use another overloaded method of toMap:

Map<String, Integer> result = givenList.stream()
  .collect(toMap(Function.identity(), String::length, (item, identicalItem) -> item));

The third parameter is a binary operation, we can specify how to deal with key conflicts. In this example, we can choose any one, because the length of the two is always the same.

Collectors.collectingAndThen()

CollectingAndThen is a special collector that can perform other actions on the results after the collection is completed. The following collects the stream elements to the List example, and then converts the result into an ImmutableList example:

List<String> result = givenList.stream()
  .collect(collectingAndThen(toList(), ImmutableList::copyOf))

Collectors.joining()

The Joining collector can be used to join elements in the string stream. Examples are as follows:

String result = givenList.stream()
  .collect(joining());

The results are as follows:

"abbcccdd"

You can also specify the separator, prefix, and suffix:

String result = givenList.stream()
  .collect(joining(" "));

The results are as follows:

"a bb ccc dd"

Look at another example:

String result = givenList.stream()
  .collect(joining(" ", "PRE-", "-POST"));

The result is:

"PRE-a bb ccc dd-POST"

Collectors.counting()

Counting is a simple collector that returns the number of elements:

Long result = givenList.stream()
  .collect(counting());

Collectors.summarizingDouble/Long/Int()

The SummarizingDouble/Long/Int collector returns the statistical result type of the numeric elements extracted in the stream. The following example obtains string length information:

DoubleSummaryStatistics result = givenList.stream()
  .collect(summarizingDouble(String::length));

The following test code is executed:

assertThat(result.getAverage()).isEqualTo(2);
assertThat(result.getCount()).isEqualTo(4);
assertThat(result.getMax()).isEqualTo(3);
assertThat(result.getMin()).isEqualTo(1);
assertThat(result.getSum()).isEqualTo(8);

Collectors.averagingDouble/Long/Int()

AveragingDouble/Long/Int is the average value of the extracted elements in the returned stream. The following example calculates the average string length:

Double result = givenList.stream()
  .collect(averagingDouble(String::length));

Collectors.summingDouble/Long/Int()

SummingDouble/Long/Int returns the sum of the extracted elements, the following calculates the sum of the length of all strings:

Double result = givenList.stream()
  .collect(summingDouble(String::length));

Collectors.maxBy()/minBy()

The MaxBy/MinBy collector returns the largest and smallest elements in the stream according to the provided Comparator instance. The largest element is calculated as follows:

Optional<String> result = givenList.stream()
  .collect(maxBy(Comparator.naturalOrder()));

It should be noted that the result is an Optional type, which forces the user to consider the empty collection

Collectors.groupingBy()

The grouping collector is used to group elements according to attributes and store them in a Map instance. The following example groups according to the length of the string and stores the result in a Set:

Map<Integer, Set<String>> result = givenList.stream()
  .collect(groupingBy(String::length, toSet()));

The test code is as follows:

assertThat(result)
  .containsEntry(1, newHashSet("a"))
  .containsEntry(2, newHashSet("bb", "dd"))
  .containsEntry(3, newHashSet("ccc"));

The second parameter is a collection, we can use any collection implementation.

Collectors.partitioningBy()

PartitioningBy is a special grouping collector that collects flow elements into the Map according to the Predicate instance, and stores the Boolean value as the key and the value as the set. The "true" key corresponds to the set of matched elements, and the "false" key is the set of non-matched elements. The sample code is as follows:

Map<Boolean, List<String>> result = givenList.stream()
  .collect(partitioningBy(s -> s.length() > 2))

The resulting Map is as follows:

{false=["a", "bb", "dd"], true=["ccc"]}

Collectors.teeing()

Find the maximum and minimum according to what we have learned so far:

List<Integer> numbers = Arrays.asList(42, 4, 2, 24);
Optional<Integer> min = numbers.stream().collect(minBy(Integer::compareTo));
Optional<Integer> max = numbers.stream().collect(maxBy(Integer::compareTo));
// do something useful with min and max

Here, we use two unused collectors, and then merge the collections to implement the corresponding business. Before Java 12, in order to achieve such a function, it was necessary to perform two operations on the stream, store the intermediate results in a temporary object, and finally merge and return.
Fortunately, java 12 provides a built-in collector to help us handle these steps: we only need to provide two collectors and a merge function.
Because the new collector tee performs operations in two different directions on the flow, it is called the T collector:

numbers.stream().collect(teeing(
  minBy(Integer::compareTo), // The first collector
  maxBy(Integer::compareTo), // The second collector
  (min, max) -> // Receives the result from those collectors and combines them
));

Guess you like

Origin blog.csdn.net/zhouzhiwengang/article/details/112332759