With Java 8:

Comparator.comparing((Person p)->p.firstName)
          .thenComparing(p->p.lastName)
          .thenComparingInt(p->p.age);

If you have accessor methods:

Comparator.comparing(Person::getFirstName)
          .thenComparing(Person::getLastName)
          .thenComparingInt(Person::getAge);

If a class implements Comparable then such comparator may be used in compareTo method:

@Override
public int compareTo(Person o){
    return Comparator.comparing(Person::getFirstName)
              .thenComparing(Person::getLastName)
              .thenComparingInt(Person::getAge)
              .compare(this, o);
}
🌐
Baeldung
baeldung.com › home › java › java – powerful comparison with lambdas
Java – Powerful Comparison with Lambdas | Baeldung
January 8, 2024 - Tips and best practices on using Java 8 lambdas and functional interfaces. ... public class Human { private String name; private int age; // standard constructors, getters/setters, equals and hashcode } Before Java 8, sorting a collection would involve creating an anonymous inner class for the Comparator used in the sort:
🌐
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 - Here, we’ve added a @Nonnull annotation to keep the examples simple. But in production code, we may need to handle the comparison of nullable fields. Java provides the Comparator interface for comparing two objects of the same type.
🌐
HowToDoInJava
howtodoinjava.com › home › java 8 › java comparator with lambda
Java Comparator with Lambda (with Examples) - HowToDoInJava
February 6, 2023 - Learn to create a Comparator instance with lambda expressions, method references and chaining multiple comparators for complex comparisons. ... The Comparator interface is used to sort a collection of objects that can be compared. The object comparison can be made using Comparable interface as well, but it restricts us by comparing objects in a specific single way only. If we want to sort this collection, based on multiple criteria/fields...
🌐
Makeinjava
makeinjava.com › home › sort objects on multiple fields /properties – comparator interface (lambda stream java 8)
Sort object on multiple fields/properties-Comparator (lamda stream java8)
January 3, 2024 - package org.learn; import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class SortObjectByField { public static void main(String[] args) { List <Person> personList = new ArrayList<>(); personList.add(new Person("Mike", "harvey", 34, "001894536")); personList.add(new Person("Nick", "young", 75, "005425676")); personList.add(new Person("Jack", "slater", 21 ,"009654153")); personList.add(new Person("gary", "hudson", 55,"00564536")); personList.add(new Person("Mike", "harvey", 21 ,"003685417")); personList.add(new Person("gary", "hudson", 25,"00452341")); System.o
🌐
Medium
bindushrestha.medium.com › how-to-order-list-of-objects-using-multiple-fields-b0b67c610613
How to sort list of objects using multiple fields? | by Bindu Shrestha | Medium
May 10, 2022 - 2. Using lambda expression · private List<Student> sortWithLambdaExp(List<Student> list) {// sort using stream and firstNamelist.sort(Comparator.comparing((Student s) -> s.getStream()).thenComparing((Student s) -> s.getFirstName()));return list;} Originally published at https://www.thecodecity.com on May 10, 2022. https://github.com/bindushrestha/comparator-sample · Comparator · Java ·
🌐
Spring Framework Guru
springframework.guru › home › comparison and sorting with lambda
Comparison and Sorting with Lambda - Spring Framework Guru
January 5, 2021 - You can compare and sort Product objects based on various properties both with and without lambda expressions. However, when you use lambda expressions it makes your code concise and easier to read. Java 8 supports the List.sort method directly, so no need to use the legacy Collections.sort method anymore.
Top answer
1 of 1
3

If you want suggestions for improvement, here is one:

The following code:

private static <T> Field getField(Class<T> clazz,String fieldName){
    Field field = null;
    try {
        field = clazz.getDeclaredField(fieldName);
    }catch(java.lang.NoSuchFieldException e){
        e.printStackTrace();
    }
    return field;
}

is best rewritten as follows:

private static <T> Field getField(Class<T> clazz,String fieldName) {
    try {
        return clazz.getDeclaredField(fieldName);
    }catch(java.lang.NoSuchFieldException e){
        throw new RuntimeException(e);
    }
}

The following code:

//Lambda comparator
Comparator<T> orderByComparator = (f1, f2) -> {

    Comparable compA = null;
    Comparable compB = null;

    // getting fields from object f1,f2
    try {
        compA =(Comparable) field.get(f1);
        compB =(Comparable) field.get(f2);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    // handling null comparators
    if(compA == null)
        return -1;
    else if(compB == null)
        return 1;

    return compA.compareTo(compB);
};

is best rewritten as follows:

Comparator<T> orderByComparator = (f1, f2) -> {
    Comparable compA, compB;
    try {
        compA = (Comparable) field.get(f1);
        compB = (Comparable) field.get(f2);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
    return Objects.compare(compA, compB, Comparator.naturalOrder());
};

in short:

  • lose the useless comments; a comment is only useful if it says something that is not immediately obvious by looking at the code

  • do not initialize variables to nonsensical values, because then the compiler will not warn you when you forget to assign something meaningful to them

  • if you do not know what to do with an exception, do not print a stack trace, throw a runtime exception instead.

Generics and lambdas have no impact on performance.

Find elsewhere
🌐
Mkyong
mkyong.com › home › java8 › java 8 lambda : comparator example
Java 8 Lambda : Comparator example - Mkyong.com
August 5, 2015 - Hi Mkyong, Can we sort multiple fields at a time using lambdas, if it is please share me the example. ... Below code is also use for sorting Collections.sort(developerList, Comparator.comparing(Developer::getAge)); ... Sorry brother i mean classes are not properly organize missed dependency class file in some of your articles. You article are great, but if you can organize the java code in proper place it would be great.
🌐
Java67
java67.com › 2019 › 06 › top-5-sorting-examples-of-comparator-and-comparable-in-java.html
6 Advanced Comparator and Comparable Examples in Java 8 | Java67
You don't need to write boilerplate code which comes with Anonymous inner class, both lambdas and method reference allow you to write clean code for comparing and sorting objects in Java 8. There are several things that have become easier in Java e.g. comparing objects by multiple parameters. Earlier, you used to write several lines of code to implement ordering on multiple fields but now it has become easier due to comparing() and thenComparing() methods of the Java 8 Comparator class, which allows you to compose a complex ordering by chaining multiple comparators.
🌐
YouTube
youtube.com › watch
How To Sort Objects On Multiple Fields Using Comparator Interface - YouTube
Sort in Java is very easy. In this tutorial we will learn how to sort using anonymous and concrete implementations of Comparator interface.
Published   April 22, 2017
🌐
Java Guides
javaguides.net › 2024 › 09 › java-8-lambda-for-sorting-list-of-objects-by-multiple-fields.html
Java 8 Lambda for Sorting a List of Objects by Multiple Fields
September 9, 2024 - thenComparing(Employee::getId): This adds a third level of comparison if both the salary and name are equal. You can chain as many thenComparing() methods as necessary for your sorting requirements. Sorting by multiple fields in Java 8 is simple and flexible with lambda expressions and the Comparator interface.
🌐
amitph
amitph.com › home › java › comparator with java lambda expression examples
Comparator with Java Lambda Expression Examples - amitph
November 22, 2024 - Next, we understood how using Lambda expressions for the same sort operation makes the code concise. We also covered using the Comparator interface’s static factory methods. The factory methods create a Comparator instance based on the given fields and conditions. Then we wrote some complex comparison operations like sorting based on multiple fields of a collection.
🌐
Medium
medium.com › @rkdixit3 › java-8-java-comparator-with-lambda-3797ccf0da59
Java 8 | Java Comparator with Lambda | by Rajesh Dixit | Medium
January 8, 2020 - // Sort all student by first nameComparator comparator = Comparator.comparing(std -> std.getFirstName());// OR you can use belowComparator comparator = Comparator.comparing(Student::getFirstName);// OR you can use belowComparator comparator = (std1, std2)-> std1.getFirstName().compareTo(std2.getFirstName());// To sort in reverse order.Comparator reversedComparator = comparator.reversed();// Sorting on multiple fields; Group by.Comparator groupByComparator= Comparator.comparing(Student::getFirstName).thenComparing(Student::getLastName);
Top answer
1 of 2
19

Change lambda expression to lambda {block}, and you don't have to specify the parameter types:

list.sort((o1, o2) -> {
    int cmp = o1.getGroup().compareTo(o2.getGroup());
    if (cmp == 0)
        cmp = Integer.compare(o1.getAge(), o2.getAge());
    if (cmp == 0)
        cmp = o1.getName().compareTo(o2.getName());
    return cmp;
});
2 of 2
16

You can use the static method Comparator.comparing to create a comparator based on a function that returns a comparable value. Such a comparator can be chained with others.

Assuming your type is called Person, you would have:

Comparator<Person> c = Comparator
        .comparing(p -> p.getGroup())
        .thenComparing(p -> p.getAge())
        .thenComparing(p -> p.getName())

If any of the getters return a primitive type, you have to use - for example - comparingInt and thenComparingInt, respectively. You can also use method references:

Comparator<Person> c = Comparator
        .comparing(Person::getGroup)
        .thenComparing(Person::getAge)
        .thenComparing(Person::getName)

But ... if your class has a natural ordering according to these values, you better let it implement the interface Comparable and write the compare logic in there:

class Person implements Comparable<Person> {
    ...
    @Override
    public int compareTo(Person other) {
        int compare = Integer.compare(getGroup(), other.getGroup());
        if (compare == 0) {
            compare = Integer.compare(getAge(), other.getAge());
        }
        if (compare == 0) {
            compare = getName.compareTo(other.getName());
        }
        return compare;
    }
}

This code snippet can also be used in a lambda expression:

list.sort((o1, o2) -> {
    int compare = Integer.compare(o1.getGroup(), o2.getGroup());
    if (compare == 0) {
        compare = Integer.compare(o1.getAge(), o2.getAge());
    }
    if (compare == 0) {
        compare = o1.getName.compareTo(o2.getName());
    }
    return compare;
});
Top answer
1 of 15
293

You can use Collections.sort as follows:

Copyprivate 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:

Copy.ThenBy(...)

I found the mechanism in Java 8 on the Comparator:

Copy.thenComparing(...)

So here is the snippet that demonstrates the algorithm.

Copy    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:

Copy@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);
    }
}
🌐
Dev.java
dev.java › learn › writing-and-combining-comparators
Dev
Leveraging inheritance in Java applications. ... Creating and using interfaces. ... Working with parameterized types. ... Using Lambda Expressions to improve the readability of your code.
🌐
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 ...