Three methods of List sorting in Java

In some special scenarios, we need to sort the List collection in the Java program. For example, get the List of all users from the third-party interface, but the List is sorted by user number from small to large by default, and our system needs to sort by user's age. At this time, we need to customize the List set. ​

There are three common methods for sorting lists:

  1. Use Comparable to sort;
  2. Sort using Comparator;
  3. For environments above JDK 8, you can also use Stream to sort.

Let's look at the specific implementation of various sorting methods.

1. Use Comparable sorting

According to the scenario designed in this article, we need to create a List set containing user lists and sort them according to the age of users. The specific implementation code is as follows:

public class ListSortExample {
    public static void main(String[] args) {
        // Create and initialize List
        List<Person> list = new ArrayList<Person>() {{
            add(new Person(1, 30, "Beijing"));
            add(new Person(2, 20, "Xi'an"));
            add(new Person(3, 40, "Shanghai"));
        }};
        // Sort using Comparable custom rules
        Collections.sort(list);
        // Print list set
        list.forEach(p -> {
            System.out.println(p);
        });
    }
}

//  The following set/get/toString uses lombok annotations
@Getter
@Setter
@ToString
class Person implements Comparable<Person> {
    private int id;
    private int age;
    private String name;

    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    @Override
    public int compareTo(Person p) {
        return p.getAge() - this.getAge();
    }
}

The execution result of the above code is shown in the following figure:

The core code of this method is as follows:

2. Sort using Comparator

Comparable is the comparison method inside the class, and comparator is the comparator outside the sorting class. To use comparator comparator, you do not need to modify the original Person class. You only need to expand a comparator of Person class. Comparator can be implemented in the following two ways:

  • Create a Comparator comparator;
  • Use Comparator anonymous class Comparator.

Among them, the second implementation method should be more concise. Let's observe the difference between the two through the following specific code.

2.1 create a Comparator

public class ListSortExample2 {
    public static void main(String[] args) {
        // Create and initialize List
        List<Person> list = new ArrayList<Person>() {{
            add(new Person(1, 30, "Beijing"));
            add(new Person(2, 20, "Xi'an"));
            add(new Person(3, 40, "Shanghai"));
        }};
        // Sorting with Comparator comparator
        Collections.sort(list, new PersonComparator());
        // Print list set
        list.forEach(p -> {
            System.out.println(p);
        });
    }
}
/**
 * New Person comparator
 */
class PersonComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return p2.getAge() - p1.getAge();
    }
}
@Getter
@Setter
@ToString
class Person {
    private int id;
    private int age;
    private String name;

    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}

The execution result of the above code is shown in the following figure:

The core implementation code of this method is as follows:

2.2 anonymous comparator

The Comparator comparator can use a more concise anonymous class to realize the sorting function. The specific implementation code is as follows:

public class ListSortExample2 {
    public static void main(String[] args) {
        // Create and initialize List
        List<Person> list = new ArrayList<Person>() {{
            add(new Person(1, 30, "Beijing"));
            add(new Person(2, 20, "Xi'an"));
            add(new Person(3, 40, "Shanghai"));
        }};
        // Sort using anonymous comparator
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p2.getAge() - p1.getAge();
            }
        });
        // Print list set
        list.forEach(p -> {
            System.out.println(p);
        });
    }
}
@Getter
@Setter
@ToString
class Person {
    private int id;
    private int age;
    private String name;
    public Person(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
}

The execution result of the above code is shown in the following figure:

3. Use Stream to sort

After JDK 8, a simpler method Stream flow can be used to realize the sorting function. Its implementation only needs one line of code. The specific implementation is as follows:

public class ListSortExample3 {
    public static void main(String[] args) {
        // Create and initialize List
        List<Person> list = new ArrayList<Person>() {{
            add(new Person(1, 30, "Beijing"));
            add(new Person(2, 20, "Xi'an"));
            add(new Person(3, 40, "Shanghai"));
        }};
        // Sorting using Stream
        list = list.stream().sorted(Comparator.comparing(Person::getAge).reversed())
                .collect(Collectors.toList());
        // Print list set
        list.forEach(p -> {
            System.out.println(p);
        });
    }
    @Getter
    @Setter
    @ToString
    static class Person {
        private int id;
        private int age;
        private String name;
        public Person(int id, int age, String name) {
            this.id = id;
            this.age = age;
            this.name = name;
        }
    }
}

Where reversed() means reverse order. If this rule is not used, it is positive order.

The execution result of the above code is shown in the following figure:

Extension: sort field is null

When sorting with Stream, an exception will occur if a null value appears in the sorted field. The specific examples are as follows:

public class ListSortExample4 {
    public static void main(String[] args) {
        // Create and initialize List
        List<Person> list = new ArrayList<Person>() {{
            add(new Person(30, "Beijing"));
            add(new Person(10, "Xi'an"));
            add(new Person(40, "Shanghai"));
            add(new Person(null, "Shanghai")); // Age is null
        }};
        // In positive order of [age], but there is a null value in the age
        list = list.stream().sorted(Comparator.comparing(Person::getAge))
                .collect(Collectors.toList());
        // Print list set
        list.forEach(p -> {
            System.out.println(p);
        });
    }
}
@Getter
@Setter
@ToString
class Person {
    private Integer age;
    private String name;

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

The execution result of the above code is shown in the following figure:

To solve the above problems, you need to give comparator Comparing passes the second parameter: comparator Nullsxxx, as shown in the following code:

public class ListSortExample4 {
    public static void main(String[] args) {
        // Create and initialize List
        List<Person> list = new ArrayList<Person>() {{
            add(new Person(30, "Beijing"));
            add(new Person(10, "Xi'an"));
            add(new Person(40, "Shanghai"));
            add(new Person(null, "Shanghai"));
        }};
        // In positive order of [age], but there is a null value in the age
        list = list.stream().sorted(Comparator.comparing(Person::getAge,
                Comparator.nullsFirst(Integer::compareTo)))
                .collect(Collectors.toList());
        // Print list set
        list.forEach(p -> {
            System.out.println(p);
        });
    }
}
@Getter
@Setter
@ToString
class Person {
    private Integer age;
    private String name;

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

Comparator.nullsFirst means to put the null value in the sorting field at the front of the collection. If you want to put the null value at the back of the collection, you can use comparator nullsLast.

The execution result of the above code is shown in the following figure:

summary

This paper introduces three List sorting methods. The first two methods are commonly used in versions before JDK 8. There are two ways to write the Comparator, which can be used in versions after JDK 8 Comparing implements sorting. If null values may appear in the sorting field, use Comparator Nullsxxx performs sorting processing (otherwise an error will be reported). ​

When the death comes, he will not be surprised, and he will not be angry without reason. Enjoy the joy of ordinary life, lifelong growth. Blogger: post-80s programmers. Hobbies: reading, writing and jogging.

Added by Vacman on Mon, 27 Dec 2021 20:43:19 +0200