Java8 Stream groupBy group sorting failure occurred in my work

Document the solution here

Expected result: Groups in reverse order of age
Actual result: The data returned is haphazard and not in reverse chronological order

Example code is as follows:

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/ * * *@author miao
 */
public class GroupBySort {

    public static void main(String[] args) {
        // Construct data
        List<Student> students = Stream.of(
                new Student("a".15),
                new Student("b".13),
                new Student("c".11),
                new Student("d".18),
                new Student("e".20)
        ).collect(Collectors.toList());

        // Enter groups in reverse order of ageMap<Integer, List<Student>> studentMap = students.stream() .sorted(Comparator.comparing(Student::getAge).reversed()) .collect(Collectors.groupingBy(Student::getAge)); System.out.println(studentMap); }}class Student {

    private String name;

    private Integer age;

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName(a) {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge(a) {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString(a) {
        return "Student{" +
                "name='" + name + '\' ' +
                ", age=" + age +
                '} '; }}Copy the code

Trying to reason

To view java.util.stream.CollectorsOf the classgroupingByMethod, source code as follows
// an input parameter
public static<T, K> Collector<T, ? , Map<K, List<T>>> groupingBy(Function<?super T, ? extends K> classifier) {
        return groupingBy(classifier, toList());
    }

// Two input parameters
public static<T, K, A, D> Collector<T, ? , Map<K, D>> groupingBy(Function<?super T, ? extends K> classifier,
                                          Collector<? super T, A, D> downstream) {
        return groupingBy(classifier, HashMap::new, downstream);
    }

// Three inputs (the final method)
public static<T, K, D, A, M extends Map<K, D>> Collector<T, ? , M> groupingBy(Function<?super T, ? extends K> classifier,
                                  Supplier<M> mapFactory,
                                  Collector<? superT, A, D> downstream) {... }Copy the code

In the second method, we see that the groupingBy interface creates a HashMap (HashMap::new) when it calls its own method. Because **hashMap, which is unordered **, is hash based on the hashcode of the key, and then put in the corresponding place. So putting into a HashMap in a certain order, and then iterating out the HashMap in a different order than putting. That’s why the above problems have arisen.

The solution

Since these three methods are of public type, we can call them directly from the outside, and the incoming parameter is given to an ordered Map. I chose LinkedHashMap.

The LinkedHashMap is briefly introduced at the end of the article

Sample code is as follows
// Paging in reverse chronological order
        Map<Integer, List<Student>> studentMap = students.stream()
                .sorted(Comparator.comparing(Student::getAge).reversed())
                .collect(Collectors.groupingBy(Student::getAge, LinkedHashMap::new, Collectors.toList()));
Copy the code
The results are as follows:

LinkedHashMapThe introduction of

  • LinkedHashMap is in order, but HashMap is out of order

  • LinkedHashMap is a subclass of HashMap, which internally maintains a bidirectional linked list to ensure the insertion order of elements. The time complexity of adding, deleting, changing, and checking is O(1).

  • The nodes of LinkedHashMap take up more space, including the before pointer to the previous node and after pointer to the next node

  • LinkedHashMap is traversed by default using the insertion order, or it can be traversed using the access order. Set accessOrder to true