Java group by sort – multiple comparators example

Java examples to do SQL-style group by sort on list of objects. It involves using multiple comparators, each of which is capable of sorting on different field in model object.

Table of Contents

1. Model class and multiple comparators
2. Comparator.thenComparing()
3. CompareToBuilder
4. ComparisonChain
5. Chained comparators

1. Model class and multiple comparators

Our model class is Employee with 4 simple fields.

package com.howtodoinjava.compare;

public class Employee implements Comparable<Employee> {

    private Integer id = -1;
    private Integer age = -1;
    private String firstName = null;
    private String lastName = null;

    public Employee(Integer id, String fName, String lName, Integer age) {
            this.id = id;
            this.firstName = fName;
            this.lastName = lName;
            this.age = age;
    }

    //Getters and Setters

    @Override
    public String toString() {
        return "\nEmployee [id=" + id + ", age=" + age + ", firstName=" + firstName + ", lastName=" + lastName + "]";
    }
}

And multiple comparators are for fields first name, last name and age.

package com.howtodoinjava.compare;

import java.util.Comparator;

public class FirstNameSorter implements Comparator<Employee> 
{
    public int compare(Employee o1, Employee o2) 
    {
        return o1.getFirstName().compareTo(o2.getFirstName());
    }
}

public class LastNameSorter implements Comparator<Employee> 
{
    public int compare(Employee o1, Employee o2) 
    {
        return o1.getLastName().compareTo(o2.getLastName());
    }
}

public class AgeSorter implements Comparator<Employee> 
{
    public int compare(Employee o1, Employee o2) 
    {
        return o1.getAge() - o2.getAge();
    }
}

2. Java group by sort – Comparator.thenComparing()

Sorting a list in Java 8 is very easy with inbuilt support for comparators chaining. You created independent field sorter by implementing Comparator interface, and the chain them in Collection.sort() method.

package com.howtodoinjava.compare;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MultipleFieldSorter 
{
    public static void main(String[] args) 
    {
        List<Employee> list = Arrays.asList(new Employee(1, "A", "B", 34), 
                                        new Employee(4, "C", "D", 30), 
                                        new Employee(3, "B", "A", 31), 
                                        new Employee(2, "D", "C", 25));

        Collections.sort(list, new FirstNameSorter()
                                .thenComparing(new LastNameSorter())
                                .thenComparing(new AgeSorter()));

        System.out.println(list);
    }
}

Program output:

[Employee [id=1, age=34, firstName=A, lastName=B], 
 Employee [id=3, age=31, firstName=B, lastName=A], 
 Employee [id=4, age=30, firstName=C, lastName=D], 
 Employee [id=2, age=25, firstName=D, lastName=C]]

3. Java group by sort – CompareToBuilder

Values are compared in the order they are appended to the builder. If any comparison returns a non-zero result, then that value will be the result returned by CompareToBuilder.toComparison() and all subsequent comparisons are skipped.

3.1. Apache common Lang3 Dependency

<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-lang3</artifactId>
	<version>3.7</version>
</dependency>

3.2. Modify compareTo() method in model

package com.howtodoinjava.compare;

import org.apache.commons.lang3.builder.CompareToBuilder;

public class Employee implements Comparable<Employee> {

    private Integer id = -1;
    private Integer age = -1;
    private String firstName = null;
    private String lastName = null;

    public Employee(Integer id, String fName, String lName, Integer age) {
        this.id = id;
        this.firstName = fName;
        this.lastName = lName;
        this.age = age;
    }

    public int compareTo(Employee o) {

        if (o == null) {
            return -1;
        }

        CompareToBuilder buider = new CompareToBuilder();

        return buider
        		.append(this.getFirstName(), o.getFirstName())
                .append(this.getLastName(), o.getLastName())
                .append(this.getAge(), o.getAge())
                .toComparison();
    }

    //getters and setters
}

3.3. Sort List

public class MultipleFieldSorter 
{
    @SuppressWarnings("unchecked")
    public static void main(String[] args) 
    {
        List<Employee> list = //list of employees;

        Collections.sort(list);

        System.out.println(list);
    }
}

3.4. CompareToBuilder with Comparator Interface

If you are not willing to modify Comparable interface the you can still utilize Comparator interface to sort list with CompareToBuilder.

package com.howtodoinjava.compare;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang3.builder.CompareToBuilder;

public class MultipleFieldSorter 
{
    public static void main(String[] args) 
    {
        List<Employee> list = Arrays.asList(new Employee(1, "A", "B", 34), 
                                        new Employee(4, "C", "D", 30), 
                                        new Employee(3, "B", "A", 31), 
                                        new Employee(2, "D", "C", 25));

        Collections.sort(list, new Comparator<Employee>() 
        {
            public int compare(Employee empOne, Employee empTwo) 
            {
                return new CompareToBuilder()
                        .append(empOne.getFirstName(), empTwo.getFirstName())
                        .append(empOne.getLastName(), empTwo.getLastName())
                        .append(empOne.getAge(), empTwo.getAge())
                        .toComparison();
            }
        });

        System.out.println(list);	//Sorted list
    }
}

4. Java group by sort – ComparisonChain

Similar to Apache Common lang’s CompareToBuilder, Google guava library provides useful class ComparisonChain to sort list of objects.

4.1. Guava Dependency

<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>23.0</version>
</dependency>

4.2. ComparisonChain Example

package com.howtodoinjava.compare;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.google.common.collect.ComparisonChain;

public class MultipleFieldSorter 
{
    public static void main(String[] args) 
    {
        List<Employee> list = Arrays.asList(new Employee(1, "A", "B", 34), 
                                        new Employee(4, "C", "D", 30), 
                                        new Employee(3, "B", "A", 31), 
                                        new Employee(2, "D", "C", 25));

        Collections.sort(list, new Comparator<Employee>() 
        {
            public int compare(Employee empOne, Employee empTwo) 
            {
                return ComparisonChain.start()
                        .compare(empOne.getFirstName(), empTwo.getFirstName())
                        .compare(empOne.getLastName(), empTwo.getLastName())
                        .compare(empOne.getAge(), empTwo.getAge())
                        .result();
            }
        });

        System.out.println(list);
    }
}

5. Java group by sort – Chained comparators

This is most basic example to use multiple comparators to sort list objects by multiple fields. In this approach, an ordered list of comparators is created and passed to a method which iterates over comparators and use each comparator to sort the current list.

5.1. Group Sorter

package com.howtodoinjava.compare;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class GroupBySorter implements Comparator<Employee> {

    private List<Comparator<Employee>> listComparators;

    public GroupBySorter(Comparator<Employee>... comparators) {
        this.listComparators = Arrays.asList(comparators);
    }

    public int compare(Employee empOne, Employee empTwo) {
        for (Comparator<Employee> comparator : listComparators) {
            int result = comparator.compare(empOne, empTwo);
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }
}

5.2. Applying group by sort on list

Now we can use above GroupBySorter to sort a list of employees. Below code sort the list of employees in following order:

  • First name
  • Last name
  • Age
package com.howtodoinjava.compare;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MultipleFieldSorter 
{
    @SuppressWarnings("unchecked")
    public static void main(String[] args) 
    {
        List<Employee> list = Arrays.asList(
                                new Employee(1, "A", "B", 34), 
                                new Employee(4, "C", "D", 30), 
                                new Employee(3, "B", "A", 31), 
                                new Employee(2, "D", "C", 25));

        Collections.sort(list, new GroupBySorter(new FirstNameSorter(), new LastNameSorter(), new AgeSorter()));

        System.out.println(list);
    }
}

Happy Learning !!

References:

ComparisonChain Java Doc
CompareToBuilder Java Doc
Comparator.thenComparing() Java Doc
Comparable Java doc

Comments

Subscribe
Notify of
guest
1 Comment
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode