Java 8 – Sort a List of Objects by Multiple Fields

Introduction

Sorting a list of objects by multiple fields is a common requirement in many applications, especially when dealing with complex data. For example, you might need to sort a list of employees first by department, and then by age within each department. Java 8 introduced the Stream API, which simplifies the sorting process and allows for easy chaining of multiple sorting conditions. In this guide, we’ll explore how to sort a list of objects by multiple fields using Java 8 Streams, covering various use cases with custom objects.

Table of Contents

  • Problem Statement
  • Solution Steps
  • Java Program
    • Sorting a List of Custom Objects by Multiple Fields
    • Sorting by Multiple Fields with Different Orders
  • Advanced Considerations
  • Conclusion

Problem Statement

The task is to create a Java program that:

  • Accepts a list of custom objects.
  • Sorts the list by multiple fields.
  • Outputs the sorted list.

Example 1:

  • Input: List of Student objects, sort first by age and then by name.
  • Output: The list of students sorted by age, and within the same age, sorted by name.

Example 2:

  • Input: List of Employee objects, sort first by department, then by salary in descending order.
  • Output: The list of employees sorted by department, and within the same department, sorted by salary in descending order.

Solution Steps

  1. Input List: Start with a list of custom objects that can either be hardcoded or provided by the user.
  2. Sort the List Using Streams: Use the sorted() method with a custom comparator to sort the list by multiple fields.
  3. Display the Result: Print the sorted list.

Java Program

Sorting a List of Custom Objects by Multiple Fields

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

/**
 * Java 8 - Sort a List of Objects by Multiple Fields
 * Author: https://www.rameshfadatare.com/
 */
public class SortByMultipleFields {

    public static void main(String[] args) {
        // Step 1: Take input list of custom objects
        List<Student> students = Arrays.asList(
                new Student("Raj", 25),
                new Student("Anita", 30),
                new Student("Vikram", 22),
                new Student("Anita", 22)
        );

        // Step 2: Sort the list by age and then by name
        List<Student> sortedStudents = students.stream()
                                               .sorted(Comparator.comparing(Student::getAge)
                                                                 .thenComparing(Student::getName))
                                               .toList();

        // Step 3: Display the result
        sortedStudents.forEach(student -> 
            System.out.println(student.getName() + ": " + student.getAge())
        );
    }
}

// Custom class Student
class Student {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

Output

Anita: 22
Vikram: 22
Raj: 25
Anita: 30

Explanation

  • The stream() method is used to create a stream from the list of Student objects.
  • The sorted() method is applied with a custom comparator that first sorts by age using Comparator.comparing(Student::getAge).
  • The thenComparing(Student::getName) method is chained to the comparator to sort by name within the same age group.
  • The result is a sorted list of Student objects, which is printed out in the order defined by the sort criteria.

Sorting by Multiple Fields with Different Orders

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

/**
 * Java 8 - Sort a List of Objects by Multiple Fields with Different Orders
 * Author: https://www.rameshfadatare.com/
 */
public class SortByMultipleFieldsDifferentOrders {

    public static void main(String[] args) {
        // Step 1: Take input list of custom objects
        List<Employee> employees = Arrays.asList(
                new Employee("Raj", "IT", 60000),
                new Employee("Anita", "HR", 75000),
                new Employee("Vikram", "IT", 55000),
                new Employee("Anita", "IT", 62000)
        );

        // Step 2: Sort the list by department, then by salary (descending)
        List<Employee> sortedEmployees = employees.stream()
                                                  .sorted(Comparator.comparing(Employee::getDepartment)
                                                                    .thenComparing(Employee::getSalary).reversed())
                                                  .toList();

        // Step 3: Display the result
        sortedEmployees.forEach(employee -> 
            System.out.println(employee.getName() + ": " + employee.getDepartment() + ", Salary: " + employee.getSalary())
        );
    }
}

// Custom class Employee
class Employee {
    private String name;
    private String department;
    private int salary;

    public Employee(String name, String department, int salary) {
        this.name = name;
        this.department = department;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public String getDepartment() {
        return department;
    }

    public int getSalary() {
        return salary;
    }
}

Output

Vikram: IT, Salary: 55000
Anita: IT, Salary: 62000
Raj: IT, Salary: 60000
Anita: HR, Salary: 75000

Explanation

  • The list of Employee objects is sorted first by department using Comparator.comparing(Employee::getDepartment).
  • The thenComparing(Employee::getSalary).reversed() method is chained to sort by salary in descending order within each department.
  • The result is a sorted list of Employee objects, which is printed out in the order defined by the sort criteria.

Advanced Considerations

  • Null Handling: When sorting by fields that might be null, you can use Comparator.nullsFirst() or Comparator.nullsLast() to handle null values gracefully. For example:

    Comparator.comparing(Employee::getDepartment, Comparator.nullsLast(Comparator.naturalOrder()))
    
  • Multiple Field Sorting in Parallel Streams: Sorting with parallel streams can lead to non-deterministic results if the sort order depends on encounter order. Ensure that the sorting logic accounts for this when using parallel streams.

  • Performance Considerations: Sorting by multiple fields using Streams is efficient for typical list sizes. However, for very large lists, consider the performance implications and test the sorting operation with your specific dataset.

Conclusion

This guide provides methods for sorting a list of objects by multiple fields using Java 8 Streams, covering both simple and complex sorting scenarios. Java 8 Streams offer a powerful and flexible way to sort lists, making your code more readable and maintainable. Depending on your specific use case, you can easily apply the techniques demonstrated in this guide to achieve the desired sorting order.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top