Detailed Explanation of Java8 Collectors Class (1)

  CollectorsClasses are utility classes for collecting and summarizing streams. It provides many methods to group, count, convert, partition, join, reduce and other operations on the stream, making it more convenient to process collection data.

        When using Collectorsthe class, we can implement different processing methods for the stream by calling the methods in it. For example, to collect the elements in the stream into a List, you can use toList()the method; to group according to specified conditions, you can use groupingBy()the method; to count the number of elements in the stream, you can use counting()the method and so on.

        In addition, the class also supports custom collectors, that is, we can write custom collectors that Collectorsimplement the interface according to our own needs , and then use them directly in the code. CollectorThis function is very useful in some complex application scenarios.

convert

toList()

  Collectors.toList()A method is a method provided by a class in Java Collectorsfor collecting elements in a stream into a collection.List

List<Integer> list = Stream.of(1, 2, 3, 4, 5)
    .collect(Collectors.toList());

In the above example, we create an integer stream containing 1~5, and use the collectmethod with the Collectors.toList()method to collect the elements in the stream into a Listcollection. The resulting listcollection contains all elements in the stream, ie {1, 2, 3, 4, 5}.

It should be noted that Collectors.toList()the method returns an immutable Listcollection, so it cannot be added or deleted, but the elements in it can be modified. If we need to get a modifiable Listcollection, we can convert it to ArrayList:

List<Integer> list = Stream.of(1, 2, 3, 4, 5)
    .collect(Collectors.toCollection(ArrayList::new));

In the above code, we use Collectors.toCollection()the method and specify the collection type to be created ArrayList, so that we can get a modifiable Listcollection.

In short, Collectors.toList()the method is very commonly used in actual development, it can conveniently collect the elements in the stream into a Listcollection, and further meet our data processing requirements.

toSet()

Collectors.toSet()A method is a method provided by a class in Java Collectorsfor collecting elements in a stream into a collection.Set

Set<Integer> set = Stream.of(1, 2, 3, 4, 5)
    .collect(Collectors.toSet());

In the above example, we create an integer stream containing 1~5, and use the collectmethod with the Collectors.toSet()method to collect the elements in the stream into a Setcollection. The resulting setcollection contains all elements in the stream, ie {1, 2, 3, 4, 5}.

It should be noted that Collectors.toSet()the method returns an immutable Setcollection, so it cannot be added or deleted, but the elements in it can be modified. If we need to get a modifiable Setcollection, we can convert it to HashSet:

Set<Integer> set = Stream.of(1, 2, 3, 4, 5)
    .collect(Collectors.toCollection(HashSet::new));

In the above code, we use Collectors.toCollection()the method and specify the collection type to be created HashSet, so that we can get a modifiable Setcollection.

Collectors.toSet()The method is very commonly used in actual development, it can conveniently collect the elements in the stream into a Setcollection, and further meet our data processing requirements.

toCollection(Supplier<C> collectionFactory)

Collectors.toCollection(Supplier<C> collectionFactory)CollectorsA method is a method provided by a class in Java for collecting elements in a stream into a collection of a specified type.

The method takes one argument, a Supplier<C>functional interface of type where Cis the type of collection to create. For example, if we wanted to create a LinkedListcollection, we could use this method like this:

List<Integer> list = Stream.of(1, 2, 3, 4, 5)
    .collect(Collectors.toCollection(LinkedList::new));

 In the above example, we use Collectors.toCollection()the method and pass in a LinkedList::newfunction to create a LinkedListcollection of type. The resulting listcollection contains all elements in the stream, ie {1, 2, 3, 4, 5}.

It should be noted that Collectors.toCollection()the method returns a modifiable collection, so it can be added or deleted.

In short, Collectors.toCollection()the method is very commonly used in actual development. It can conveniently collect the elements in the stream into a specified type of collection to further meet our data processing needs. At the same time, this method is very flexible, and different types of collection factories can be passed in to create different types of collections according to actual needs.

toConcurrentMap

Collectors.toConcurrentMap()A method is a method provided by a class in Java Collectorsfor collecting the elements in a stream into a concurrent . MapIt has several overloads, the simplest of which does not require an Mapimplementation type of passed in:

ConcurrentMap<Integer, String> concurrentMap = Stream.of("a", "b", "c")
    .collect(Collectors.toConcurrentMap(
        String::length,
        Function.identity()
    ));

In the above example, we used toConcurrentMap()the method to create a concurrency Mapwith the length of the string as the key and the string itself as the value. Specifically, this method accepts two parameters:

  • A functional interface  keyMapperthat expresses how to convert elements in the stream into keys;
  • A functional interface  valueMapperexpressing how to convert elements of a stream into values.

For the stream in the above example, String::lengththe functional interface converts the string to its length, and Function.identity()the functional interface maps the string to itself. The result thus obtained is:

{1=a, 2=b, 3=c}

 It should be noted that when there are duplicate keys in the stream, toConcurrentMap()the method will throw an IllegalStateExceptionexception. We can specify how to solve the problem of duplicate keys through the third parameter. For example, if we want to combine the values ​​corresponding to duplicate keys into one string, we can use this method like this:

ConcurrentMap<Integer, String> concurrentMap = Stream.of("aa", "bbb", "cc")
    .collect(Collectors.toConcurrentMap(
        String::length,
        Function.identity(),
        (s1, s2) -> s1 + "|" + s2
    ));

 In the above example, we pass in a merge function (s1, s2) -> s1 + "|" + s2, if there are duplicate keys, the corresponding values ​​will be merged and |separated by . The result thus obtained is:

{2=aa|cc, 3=bbb}

Collectors.toConcurrentMap()The method is very commonly used in actual development, it can conveniently collect the elements in the stream into a concurrent Map, and provides a rich way to deal with problems such as duplicate keys.

toMap

Collectors.toMap()Mapmethod is a method used to collect the elements of the stream into a . It has several overloads, the simplest of which does not require an Mapimplementation type of passed in:

Map<Integer, String> map = Stream.of("a", "b", "c")
    .collect(Collectors.toMap(
        String::length,
        Function.identity()
    ));

In the example above, we toMap()created one using the method Map, which takes the length of the string as the key and the string itself as the value. Specifically, this method accepts two parameters:

  • A functional interface  keyMapperthat expresses how to convert elements in the stream into keys;
  • A functional interface  valueMapperexpressing how to convert elements of a stream into values.

For the stream in the above example, String::lengththe functional interface converts the string to its length, and Function.identity()the functional interface maps the string to itself. The result thus obtained is:

{1=a, 2=b, 3=c}

 It should be noted that when there are duplicate keys in the stream, toMap()the method will throw an IllegalStateExceptionexception. We can specify how to solve the problem of duplicate keys through the third parameter. For example, if we want to combine the values ​​corresponding to duplicate keys into one string, we can use this method like this:

Map<Integer, String> map = Stream.of("aa", "bbb", "cc")
    .collect(Collectors.toMap(
        String::length,
        Function.identity(),
        (s1, s2) -> s1 + "|" + s2
    ));

In the above example, we pass in a merge function (s1, s2) -> s1 + "|" + s2, if there are duplicate keys, the corresponding values ​​will be merged and |separated by . The result thus obtained is:

{2=aa|cc, 3=bbb}

Collectors.toMap()The method is very commonly used in actual development, it can conveniently collect the elements in the stream into one Map, and provides rich ways to deal with problems such as duplicate keys.

group

groupingBy(Function<? super T, ? extends K> classifier)

Collectors.groupingBy()CollectorsThe method is a method provided by the class in Java to group the elements in the stream according to the specified classifier. Specifically, the method accepts one parameter:

  • A functional interface  classifierrepresenting how to classify elements in a stream.

This method has two overloaded forms, the simplest of which only needs to pass in a classifier function:

Map<K, List<T>> map = stream.collect(Collectors.groupingBy(classifier));

in,

  • stream is the stream to be processed;
  • classifier is a functional interface for mapping each element in the stream to a sort key  K.

For example, we have a list of strings and want to group by string length:

List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
Map<Integer, List<String>> map = list.stream().collect(Collectors.groupingBy(String::length));

 In the code above, we use String::lengththe functional interface to convert a string to its length and use it as a sort key. The result of the operation is as follows:

{3=[date], 5=[apple, cherry], 6=[banana], 10=[elderberry]}

It should be noted that groupingBy()the method returns an Mapobject, where the key is the category key and the value is a list of elements corresponding to the category key. In the above example, there are two strings of length 5, so they are both added to the same list.

In addition to the above methods, Collectors.groupingBy()the method also provides a second parameter downstream, which is used to further process the grouped results. For example, we can use Collectors.counting()the method to count the number of elements in each group:

Map<Integer, Long> map = list.stream()
    .collect(Collectors.groupingBy(String::length, Collectors.counting()));

In the above code, we use Collectors.counting()the method as the downstream parameter, count the number of elements in each group, and encapsulate the result as a Long type. The result of the operation is as follows:

{3=1, 5=2, 6=1, 10=1}

Collectors.groupingBy()Method is a very powerful grouping operation in Java, which can group the elements in the stream according to the specified classifier, and supports various further processing methods, such as statistics, aggregation, sorting, etc.

groupingByConcurrent(Function<? super T, ? extends K> classifier)

  Collectors.groupingByConcurrent()The method Collectors.groupingBy()is very similar to the method, both are used to group the elements in the stream according to the specified classifier. The difference Collectors.groupingBy()is that Collectors.groupingByConcurrent()the method returns a thread-safe (concurrent) ConcurrentMapobject.

groupingByConcurrent()The usage of the method groupingBy()is similar to , and there are also two overloaded forms. The simplest form is as follows:

ConcurrentMap<K, List<T>> map = stream.collect(Collectors.groupingByConcurrent(classifier));

in,

  • stream is the stream to be processed;
  • classifier is a functional interface for mapping each element in the stream to a sort key  K.

For example, we have a list of strings and want to group by string length:

List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
ConcurrentMap<Integer, List<String>> map = list.parallelStream()
    .collect(Collectors.groupingByConcurrent(String::length));

In the above code, we use parallelStream()the method to convert the list into a parallel stream for grouping operations in a multi-threaded environment. The result of the operation is as follows:

{3=[date], 5=[apple, cherry], 6=[banana], 10=[elderberry]}

        It should be noted that groupingByConcurrent()the method , groupingBy()like the method, returns a Mapobject, where the key is the category key and the value is a list of elements corresponding to the category key. In the above example, there are two strings of length 5, so they are both added to the same list.

  Collectors.groupingByConcurrent()method Collectors.groupingBy()is very similar to method and can be thought of as a thread-safe and non-thread-safe version of the grouping operation. In a multi-threaded environment, groupingByConcurrent()the method has better performance and concurrency, and is suitable for processing large-scale data and high concurrency scenarios, but correspondingly it will occupy more system resources.

mapping()

   Collectors.mapping()The method is a new collector (Collector) in Java 8. It can be used to map elements in a stream before processing them with other collectors.

mapping()The method is defined as follows:

public static <T, U, A, R> Collector<T, ?, R> mapping(
    Function<? super T, ? extends U> mapper,
    Collector<? super U, A, R> downstream)

in,

  • mapper is a functional interface for mapping each element in the stream;
  • downstream Is another collector for further operations on the mapped elements.

  mapping()method applies mapperthe function to the elements in the stream and passes the result to downstreamthe collector for further processing. Finally, the results are combined to form the final result.

        For example, we have a list of strings and want to count the number of occurrences of characters in each string. You can use mapping()the method to map each string to an Mapobject with the number of occurrences of a character, and then use the method to merge toMap()all the to get the final result:Map

List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");

Map<Character, Integer> resultMap = list.stream()
    .flatMapToInt(String::chars)     // 将每个字符串转换为字符流
    .mapToObj(c -> (char) c)         // 将每个字符转换为包装类型
    .collect(Collectors.mapping(
        Function.identity(),         // 将字符作为 KEY
        Collectors.groupingBy(c -> c, Collectors.summingInt(c -> 1)) // 统计每个字符出现的次数
    ))
    .entrySet().stream()
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        In the above code, we first use flatMapToInt()the method to convert the string to a IntStreamobject, and then use mapToObj()the method to convert each character to a wrapper type. Then we use mapping()the method to group and count each character, and get multiple Mapobjects, and finally use toMap()the method to combine them to get the final result.

        It should be noted that in mapping()the method, what we pass to the second parameter is Collectors.groupingBy()the method, which means that we have grouped the elements first. The second groupingBy()parameter of the method is Collectors.summingInt()the method, which means that we perform a sum operation on each group of elements.

  Collectors.mapping()The method is very flexible and can be used in conjunction with other collectors to achieve more complex data processing operations

Partition

partitioningBy(Predicate<? super T> predicate)

        Collectors.partitioningBy(Predicate<? super T> predicate) is a collector (Collector) in Java 8, which is used to partition the elements in the Stream according to the conditions of the Predicate, and save the result of the partition to a Map object .

        The parameter predicate of this method is a predicate (Predicate), which represents the condition for filtering the elements in the Stream, and its return value is a Boolean type. Specifically, if the method returns true, the element should be sorted into the partition's true list; if it returns false, the element should be sorted into the partition's false list.

        For example, suppose there is a List<Student> students of Student type, we can use the Collectors.partitioningBy() method to partition it according to whether the student's score is greater than or equal to 60, and save the partition result into a Map object:

Map<Boolean, List<Student>> result = students.stream()
    .collect(Collectors.partitioningBy(s -> s.getScore() >= 60));

         In the above code, we use the stream() method to convert the List into a Stream, then use the Collectors.partitioningBy() method to partition the elements in the Stream, and save the result of the partition to the result of type Map<Boolean, List<Student>> object. In the resulting Map object, the part whose key is true contains all students whose scores are greater than or equal to 60 points, and the part whose key is false contains all students whose scores are less than 60 points.

        When we need to partition the elements in the Stream according to a certain attribute, we can use the method reference instead of the Lambda expression. For example, assuming that the Student type has a boolean type attribute isMale, indicating whether the student is male, we can partition the students by the following code:

Map<Boolean, List<Student>> result = students.stream()
    .collect(Collectors.partitioningBy(Student::isMale));

        In the above code, Student::isMale represents a static method in the Student type, which is used to return whether the student is male. Therefore, we can pass this method as a Predicate parameter to the Collectors.partitioningBy() method to realize the function of partitioning students according to their gender.

        In short, Collectors.partitioningBy(Predicate<? super T> predicate) is a very useful collector in Java 8, which can partition the elements in the Stream according to arbitrary conditions, and save the result of the partition into a Map object , which provides great convenience for us to process data.

partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream)

        Collectors.partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream) is a collector (Collector) in Java 8, which is used to partition the elements in Stream according to the conditions of Predicate , and apply a downstream collector (downstream) to each partition, saving the result of the partition into a Map object.

        The first parameter predicate of this method is a predicate (Predicate), which represents the condition for filtering the elements in the Stream. Elements that meet the conditions will be assigned to the true list of the partition; otherwise, they will be assigned to the false list of the partition.

        The second parameter downstream is a downstream collector (Collector), which will act on the elements of each partition. The type received by downstream is T, the type of the intermediate accumulation result is A, and the final return value type is D. Usually, we use other collectors as downstream, such as Collectors.toList(), Collectors.toSet(), Collectors.summingInt() and other methods.

        Below, we use an example to explain the usage of Collectors.partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream). Suppose there is a list List<Person> persons of Person type, we need to partition people whose age is greater than or equal to 18 according to gender, and save the names of the people in each partition into a List<String>. You can use the following code to achieve:

Map<Boolean, List<String>> result = persons.stream()
    .collect(Collectors.partitioningBy(
        p -> p.getAge() >= 18,
        Collectors.mapping(Person::getName, Collectors.toList())));

        In the above code, we use the stream() method to convert the List into a Stream, then use the Collectors.partitioningBy() method to partition the elements in the Stream, and save the partition results to the Map<Boolean, List<String>> type result object. Among them, the first parameter p -> p.getAge() >= 18 means to partition people whose age is greater than or equal to 18, and the second parameter Collectors.mapping(Person::getName, Collectors.toList()) means to partition Each person's name in is mapped to a List, and this List is used as the value of the partition. This way we can partition by age and gender and get a list of names of the people in each partition.

        In short, Collectors.partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream) is a very useful collector in Java 8, which can partition the elements in Stream according to arbitrary conditions , and apply a downstream collector to each partition, and save the result of the partition into a Map object, which provides great convenience for us to process data. At the same time, by choosing a reasonable downstream collector, we can achieve more complex partition operations.

Guess you like

Origin blog.csdn.net/Ascend1977/article/details/130952893