You can use Collections.sort as follows:

private static void order(List<Person> persons) {

    Collections.sort(persons, new Comparator() {

        public int compare(Object o1, Object o2) {

            String x1 = ((Person) o1).getName();
            String x2 = ((Person) o2).getName();
            int sComp = x1.compareTo(x2);

            if (sComp != 0) {
               return sComp;
            } 

            Integer x1 = ((Person) o1).getAge();
            Integer x2 = ((Person) o2).getAge();
            return x1.compareTo(x2);
    }});
}

List<Persons> is now sorted by name, then by age.

String.compareTo "Compares two strings lexicographically" - from the docs.

Collections.sort is a static method in the native Collections library. It does the actual sorting, you just need to provide a Comparator which defines how two elements in your list should be compared: this is achieved by providing your own implementation of the compare method.

Answer from Richard H on Stack Overflow
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › sorting a stream by multiple fields in java
Sorting a Stream by Multiple Fields in Java - Group by sort example
March 10, 2022 - //first name comparator Comparator<Employee> compareByFirstName = Comparator.comparing( Employee::getFirstName ); //last name comparator Comparator<Employee> compareByLastName = Comparator.comparing( Employee::getLastName ); //Compare by first name and then last name (multiple fields) Comparator<Employee> compareByFullName = compareByFirstName.thenComparing(compareByLastName); //Using Comparator - pseudo code list.stream().sorted( comparator ).collect(); Given below is an example of using thenComparing() to create Comparator which is capable of sorting the employees’ list by their first name
Top answer
1 of 15
293

You can use Collections.sort as follows:

private static void order(List<Person> persons) {

    Collections.sort(persons, new Comparator() {

        public int compare(Object o1, Object o2) {

            String x1 = ((Person) o1).getName();
            String x2 = ((Person) o2).getName();
            int sComp = x1.compareTo(x2);

            if (sComp != 0) {
               return sComp;
            } 

            Integer x1 = ((Person) o1).getAge();
            Integer x2 = ((Person) o2).getAge();
            return x1.compareTo(x2);
    }});
}

List<Persons> is now sorted by name, then by age.

String.compareTo "Compares two strings lexicographically" - from the docs.

Collections.sort is a static method in the native Collections library. It does the actual sorting, you just need to provide a Comparator which defines how two elements in your list should be compared: this is achieved by providing your own implementation of the compare method.

2 of 15
204

For those able to use the Java 8 streaming API, there is a neater approach that is well documented here: Lambdas and sorting

I was looking for the equivalent of the C# LINQ:

.ThenBy(...)

I found the mechanism in Java 8 on the Comparator:

.thenComparing(...)

So here is the snippet that demonstrates the algorithm.

    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));

Check out the link above for a neater way and an explanation about how Java's type inference makes it a bit more clunky to define compared to LINQ.

Here is the full unit test for reference:

@Test
public void testChainedSorting()
{
    // Create the collection of people:
    ArrayList<Person> people = new ArrayList<>();
    people.add(new Person("Dan", 4));
    people.add(new Person("Andi", 2));
    people.add(new Person("Bob", 42));
    people.add(new Person("Debby", 3));
    people.add(new Person("Bob", 72));
    people.add(new Person("Barry", 20));
    people.add(new Person("Cathy", 40));
    people.add(new Person("Bob", 40));
    people.add(new Person("Barry", 50));

    // Define chained comparators:
    // Great article explaining this and how to make it even neater:
    // http://blog.jooq.org/2014/01/31/java-8-friday-goodies-lambdas-and-sorting/
    Comparator<Person> comparator = Comparator.comparing(person -> person.name);
    comparator = comparator.thenComparing(Comparator.comparing(person -> person.age));

    // Sort the stream:
    Stream<Person> personStream = people.stream().sorted(comparator);

    // Make sure that the output is as expected:
    List<Person> sortedPeople = personStream.collect(Collectors.toList());
    Assert.assertEquals("Andi",  sortedPeople.get(0).name); Assert.assertEquals(2,  sortedPeople.get(0).age);
    Assert.assertEquals("Barry", sortedPeople.get(1).name); Assert.assertEquals(20, sortedPeople.get(1).age);
    Assert.assertEquals("Barry", sortedPeople.get(2).name); Assert.assertEquals(50, sortedPeople.get(2).age);
    Assert.assertEquals("Bob",   sortedPeople.get(3).name); Assert.assertEquals(40, sortedPeople.get(3).age);
    Assert.assertEquals("Bob",   sortedPeople.get(4).name); Assert.assertEquals(42, sortedPeople.get(4).age);
    Assert.assertEquals("Bob",   sortedPeople.get(5).name); Assert.assertEquals(72, sortedPeople.get(5).age);
    Assert.assertEquals("Cathy", sortedPeople.get(6).name); Assert.assertEquals(40, sortedPeople.get(6).age);
    Assert.assertEquals("Dan",   sortedPeople.get(7).name); Assert.assertEquals(4,  sortedPeople.get(7).age);
    Assert.assertEquals("Debby", sortedPeople.get(8).name); Assert.assertEquals(3,  sortedPeople.get(8).age);
    // Andi     : 2
    // Barry    : 20
    // Barry    : 50
    // Bob      : 40
    // Bob      : 42
    // Bob      : 72
    // Cathy    : 40
    // Dan      : 4
    // Debby    : 3
}

/**
 * A person in our system.
 */
public static class Person
{
    /**
     * Creates a new person.
     * @param name The name of the person.
     * @param age The age of the person.
     */
    public Person(String name, int age)
    {
        this.age = age;
        this.name = name;
    }

    /**
     * The name of the person.
     */
    public String name;

    /**
     * The age of the person.
     */
    public int age;

    @Override
    public String toString()
    {
        if (name == null) return super.toString();
        else return String.format("%s : %d", this.name, this.age);
    }
}
🌐
Javaprogramto
javaprogramto.com › 2020 › 08 › java-8-sorting-stream-on-multiple-fields.html
Java 8 – Sorting Stream On Multiple Fields with Comparator.thenComparing() JavaProgramTo.com
Instead of Collections.sort() method, used stream.sorted() method. Finally, passed the multipleFieldsComparator1 to thenComparing() method and collected the sorted list into to new List.
🌐
Java67
java67.com › 2021 › 09 › java-comparator-multiple-fields-example.html
How to sort a List or Stream by Multiple Fields in Java? Comparator comparing() + thenComparing Example | Java67
If your natural ordering requires multiple fields comparing then go for it, otherwise use a Comparator. In general, the code for sorting which defines natural order is implemented using Comparable and resides in the same class but Comparator ...
🌐
Baeldung
baeldung.com › home › java › java collections › sort collection of objects by multiple fields in java
Sort Collection of Objects by Multiple Fields in Java | Baeldung
January 8, 2024 - In this article, we learned different approaches for comparing on multiple fields when sorting collections of objects.
🌐
YouTube
youtube.com › watch
Sorting a List with multiple fields using streams, Java8+ - YouTube
This videos explains how to sort the list with multiple fields using streams, Java8+
Published   July 4, 2023
🌐
Codez Up
codezup.com › home › sorting list and stream on multiple fields java 8 example
Sorting List and Stream on Multiple Fields Java 8 Example | Codez Up
September 24, 2021 - This tutorial will help you to find out the solution to such requirements. Let’s start the tutorial. We perform sorting on stream and list of objects using the multiple fields using the Comparators and Comparator.thenComparing() method.
🌐
Benchresources
benchresources.net › home › java › java 8 – sorting list of objects on multiple fields
Java 8 - Sorting list of objects on multiple fields - BenchResources.Net
October 18, 2022 - All the above mentioned approaches produces same result but the way they are implemented using Java 8 Comparator differs · package net.bench.resources.stream.sorting.multiple.fields; public class Customer { // member variables String custName; String custCity; Integer custAge; // 3-arg parameterized constructor // getters & setters // toString() method }
Find elsewhere
🌐
GeeksforGeeks
geeksforgeeks.org › java › stream-sorted-in-java
Stream sorted() in Java - GeeksforGeeks
January 23, 2026 - Example 2: This code demonstrates sorting a stream of Point objects by their x coordinate using Stream.sorted() with a custom comparator. ... import java.util.*; class Point { Integer x, y; Point(Integer x, Integer y) { this.x = x; this.y = y; } public String toString() { return x + ", " + y; } } class GFG { public static void main(String[] args) { List<Point> list = Arrays.asList( new Point(10, 20), new Point(5, 10), new Point(1, 100), new Point(50, 2000) ); list.stream() .sorted((p1, p2) -> p1.x.compareTo(p2.x)) .forEach(System.out::println); } }
🌐
LinkedIn
linkedin.com › pulse › sorting-stream-multiple-fields-java-narendra-reddy-kadiri
Sorting a Data by Multiple Fields in Java
June 15, 2022 - collect(Collectors.toList()); System.out.println("sorted Employees list is: \n " + sortedEmployees); } /** * Setting test data * @return List of employees */ public List<Employee> getEmployeeList() { return Arrays.asList( new Employee("Anna", "Anthoni", "10001", "IT-1", getDate("06/12/1990")), new Employee("Anna", "A", "10002", "IT-1", getDate("04/24/1991")), new Employee("Adam", "B", "10003", "IT-1", getDate("04/24/1991")), new Employee("Barbera", "B", "10004", "IT-1", getDate("06/12/1991")), new Employee("Barbera", "Kondety", "10005", "IT-1", getDate("06/12/1991")), new Employee("Cameron", "
🌐
Medium
medium.com › @AlexanderObregon › javas-stream-sorted-method-explained-52b9b25e9f84
Java’s Stream.sorted() Method Explained | Medium
December 26, 2024 - The Comparator.comparingInt method provides a convenient way to create a comparator for integer fields. The lazy behavior of streams means that no sorting occurs until a terminal operation triggers the processing. This is an important feature because intermediate operations like filtering or mapping can alter the stream before sorting is applied. Here’s an example that combines filtering and sorting: import java.util.Arrays; import java.util.List; public class LazyEvaluationExample { public static void main(String[] args) { List<String> names = Arrays.asList("Oliver", "Jack", "Harry", "Jacob", "George"); names.stream() .filter(name -> name.length() > 4) .sorted() .forEach(System.out::println); } }
🌐
Medium
medium.com › @rtj1857 › sorting-in-java-using-streams-dc7fd6597872
Sorting in Java using Streams.. We will learn how to sort a list of… | by Ramit Raj | Medium
December 21, 2023 - List<Employee> sortedEmployee= list.stream().filter(Objects::nonNull) .sorted(Comparator.comparing(Employee::getSalary) .reversed() .thenComparing(Employee::getName)) .toList(); So similarly way we can sort till N number of fields where total field present in class is N using .thenComparing and we can perform in ascending or descending order(using .reversed() method). Happy Learning!! Thank You!! Java ·
🌐
Knpcode
knpcode.com › 2021 › 09 › java-stream-sort-on-multiple-fields.html
Java Stream Sort on Multiple Fields | KnpCode
1. Stream<T> sorted(Comparator<? super T> comparator)- sorts the elements of this stream according to the provided Comparator. 2. Since sorting is to be done on multiple fields for that you can compose several Comparators using thenComparing(Comparator<? super T> other) method.
🌐
Blogger
java8example.blogspot.com › 2020 › 08 › java-8-stream-sort-multiple-fields-example.html
Java 8 Stream Sorting Multiple Fields Examples Java8Example
August 16, 2020 - import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class SortMultipleFieldsSorted { public static void main(String[] args) { Employee e1 = new Employee(111, "Hari", 30); Employee e2 = new Employee(222, "Jool", 35); Employee e3 = new Employee(333, "Hari", 28); Employee e4 = new Employee(444, "Jool", 23); List<Employee> unsortredList = Arrays.asList(e1, e2, e3, e4); Comparator<Employee> idEmployeeComparator = Comparator.comparing(Employee::getName); Comparator<Employee> titleEmployeeComparator = Comparator.comparing(Employee::g
🌐
amitph
amitph.com › home › java › sorting collection of objects by multiple fields in java
Sorting Collection of Objects by Multiple Fields in Java - amitph
February 10, 2026 - We will sort this Collection of custom objects by comparing the multiple fields of the class. The compare() method of the Comparator interface is a function that compares two Java Objects of the same type.
Top answer
1 of 15
187

(originally from Ways to sort lists of objects in Java based on multiple fields)

Original working code in this gist

Using Java 8 lambda's (added April 10, 2019)

Java 8 solves this nicely by lambda's (though Guava and Apache Commons might still offer more flexibility):

Collections.sort(reportList, Comparator.comparing(Report::getReportKey)
            .thenComparing(Report::getStudentNumber)
            .thenComparing(Report::getSchool));

Thanks to @gaoagong's answer below.

Note that one advantage here is that the getters are evaluated lazily (eg. getSchool() is only evaluated if relevant).

Messy and convoluted: Sorting by hand

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        int sizeCmp = p1.size.compareTo(p2.size);  
        if (sizeCmp != 0) {  
            return sizeCmp;  
        }  
        int nrOfToppingsCmp = p1.nrOfToppings.compareTo(p2.nrOfToppings);  
        if (nrOfToppingsCmp != 0) {  
            return nrOfToppingsCmp;  
        }  
        return p1.name.compareTo(p2.name);  
    }  
});  

This requires a lot of typing, maintenance and is error prone. The only advantage is that getters are only invoked when relevant.

The reflective way: Sorting with BeanComparator

ComparatorChain chain = new ComparatorChain(Arrays.asList(
   new BeanComparator("size"), 
   new BeanComparator("nrOfToppings"), 
   new BeanComparator("name")));

Collections.sort(pizzas, chain);  

Obviously this is more concise, but even more error prone as you lose your direct reference to the fields by using Strings instead (no typesafety, auto-refactorings). Now if a field is renamed, the compiler won’t even report a problem. Moreover, because this solution uses reflection, the sorting is much slower.

Getting there: Sorting with Google Guava’s ComparisonChain

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        return ComparisonChain.start().compare(p1.size, p2.size).compare(p1.nrOfToppings, p2.nrOfToppings).compare(p1.name, p2.name).result();  
        // or in case the fields can be null:  
        /* 
        return ComparisonChain.start() 
           .compare(p1.size, p2.size, Ordering.natural().nullsLast()) 
           .compare(p1.nrOfToppings, p2.nrOfToppings, Ordering.natural().nullsLast()) 
           .compare(p1.name, p2.name, Ordering.natural().nullsLast()) 
           .result(); 
        */  
    }  
});  

This is much better, but requires some boiler plate code for the most common use case: null-values should be valued less by default. For null-fields, you have to provide an extra directive to Guava what to do in that case. This is a flexible mechanism if you want to do something specific, but often you want the default case (ie. 1, a, b, z, null).

And as noted in the comments below, these getters are all evaluated immediately for each comparison.

Sorting with Apache Commons CompareToBuilder

Collections.sort(pizzas, new Comparator<Pizza>() {  
    @Override  
    public int compare(Pizza p1, Pizza p2) {  
        return new CompareToBuilder().append(p1.size, p2.size).append(p1.nrOfToppings, p2.nrOfToppings).append(p1.name, p2.name).toComparison();  
    }  
});  

Like Guava’s ComparisonChain, this library class sorts easily on multiple fields, but also defines default behavior for null values (ie. 1, a, b, z, null). However, you can’t specify anything else either, unless you provide your own Comparator.

Again, as noted in the comments below, these getters are all evaluated immediately for each comparison.

Thus

Ultimately it comes down to flavor and the need for flexibility (Guava’s ComparisonChain) vs. concise code (Apache’s CompareToBuilder).

Bonus method

I found a nice solution that combines multiple comparators in order of priority on CodeReview in a MultiComparator:

class MultiComparator<T> implements Comparator<T> {
    private final List<Comparator<T>> comparators;

    public MultiComparator(List<Comparator<? super T>> comparators) {
        this.comparators = comparators;
    }

    public MultiComparator(Comparator<? super T>... comparators) {
        this(Arrays.asList(comparators));
    }

    public int compare(T o1, T o2) {
        for (Comparator<T> c : comparators) {
            int result = c.compare(o1, o2);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }

    public static <T> void sort(List<T> list, Comparator<? super T>... comparators) {
        Collections.sort(list, new MultiComparator<T>(comparators));
    }
}

Ofcourse Apache Commons Collections has a util for this already:

ComparatorUtils.chainedComparator(comparatorCollection)

Collections.sort(list, ComparatorUtils.chainedComparator(comparators));
2 of 15
156

Do you see anything wrong with the code?

Yes. Why are you adding the three fields together before you compare them?

I would probably do something like this: (assuming the fields are in the order you wish to sort them in)

@Override public int compare(final Report record1, final Report record2) {
    int c;
    c = record1.getReportKey().compareTo(record2.getReportKey());
    if (c == 0)
       c = record1.getStudentNumber().compareTo(record2.getStudentNumber());
    if (c == 0)
       c = record1.getSchool().compareTo(record2.getSchool());
    return c;
}
🌐
amitph
amitph.com › home › java › sorting collections with java streams api
Sorting Collections with Java Streams API - amitph
November 22, 2024 - We used a Java Lambda expression-based Comparator implementation to sort a collection of objects. In the end, we collect the sorted objects in a List. By default, both Java Stream sorted() methods sort the elements in the forward or ascending order.