Java 8 – Sorting list of objects on multiple fields

In one of the previous article, we discussed on how to sort list of objects on multiple field/parameters where we have coded/developed our own customized Comparator.

We will reuse the same example to sort on multiple fields using Java 8 Comparator in a more elegant way using different approaches.

1. Comparator interface :

  • This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference
  • A comparison function, which imposes a total ordering on some collection of objects
  • Comparators can be passed to a sort method (such as Collections.sort or Arrays.sort) to allow precise control over the sort order



2. Multiple Sorting using Comparator :

  • Using Java 8 Comparator, we are going to sort list of Customer objects on the basis of three attributes viz.; name, city and their age
  • First, we are going to sort the list according to their name
  • Second, if name of the 2/3 customers are same then we are going to sort on the basis of their city
  • Third and finally, if customers name/city are same then we are going to sort on the basis of their age in ascending order
  • We can achieve this target using different approaches namely,
    1. using Lambda Expression
    2. using Method Reference
    3. Inline sorting using Comparator
    4. Collection.sort() method
    5. Arrays.sort() method
  • All the above mentioned approaches produces same result but the way they are implemented using Java 8 Comparator differs

Customer.java

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
}

2.1 using Lambda Expression

  • In this approach, we are going to define 3 different Comparators using Lambda Expression as shown below
  • 1st Name Comparator :- (cust1, cust2) -> cust1.getCustName().compareTo(cust2.getCustName())
  • 2nd City Comparator :- (cust1, cust2) -> cust1.getCustCity().compareTo(cust2.getCustCity())
  • 3rd Age Comparator :- (cust1, cust2) -> cust1.getCustAge().compareTo(cust2.getCustAge())
  • Finally, passing above comparators to sorted() method using thenComparing() method one-by-one
package net.bench.resources.stream.sorting.multiple.fields;

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

public class MultipleSortingUsingJava8Lambda {

	// customer list
	private static List<Customer> getUnSortedCustomers() {

		return Arrays.asList(
				new Customer("Shalini", "Chennai", 60),
				new Customer("Sneha", "Pune",  73),
				new Customer("Simran", "Bangalore", 37),
				new Customer("Trisha", "Hyderabad", 52),
				new Customer("Shalini", "Chennai", 70),
				new Customer("Abirami", "Bangalore", 48),
				new Customer("Trisha", "Mangalore", 45),
				new Customer("Sneha", "Pune", 62),
				new Customer("Shalini", "Chennai",  50)
				);
	}

	// main() method
	public static void main(String[] args) {

		// get customer list
		List<Customer> unsortedCustomerList = getUnSortedCustomers();

		System.out.println("Before Sorting: Customer list :- \n");
		unsortedCustomerList.stream().forEach(System.out::println);


		System.out.println("\n\nSorted Customer list on multiple fields"
				+ " using Lambda Expression :- \n");

		// 1. customer Name comparator
		Comparator<Customer> nameComparatorLEx = 
				(cust1, cust2) -> cust1.getCustName().compareTo(cust2.getCustName());

		// 2. customer City comparator
		Comparator<Customer> cityComparatorLEx = 
				(cust1, cust2) -> cust1.getCustCity().compareTo(cust2.getCustCity());

		// 3. customer Age comparator
		Comparator<Customer> ageComparatorLEx =  
				(cust1, cust2) -> cust1.getCustAge().compareTo(cust2.getCustAge());

		// sorting on multiple fields (3-level) using Lambda expression
		List<Customer> sortedCustomerList = unsortedCustomerList
				.stream()
				.sorted(
						nameComparatorLEx // 1st compare Name
						.thenComparing(cityComparatorLEx) // then 2nd compare City
						.thenComparing(ageComparatorLEx)) // then 3rd compare Age
				.collect(Collectors.toList()); // collect sorted customers to new list

		// print new list to console using forEach()
		sortedCustomerList.stream().forEach(cust -> System.out.println(cust));
	}
}

Output:

Before Sorting: Customer list :- 

Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Shalini, custCity=Chennai, custAge=50]


Sorted Customer list on multiple fields using Lambda Expression :- 

Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Shalini, custCity=Chennai, custAge=50]
Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]

2.2 using Method reference

  • In this approach, we are going to define 3 different Comparators using Method Reference as shown below
  • 1st Name Comparator :- Comparator.comparing(Customer::getCustName)
  • 2nd City Comparator :- Comparator.comparing(Customer::getCustCity)
  • 3rd Age Comparator :- Comparator.comparing(Customer::getCustAge)
  • Finally, passing above comparators to sorted() method using thenComparing() method one-by-one
package net.bench.resources.stream.sorting.multiple.fields;

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

public class MultipleSortingUsingJava8MethodReference {

	// customer list
	private static List<Customer> getUnSortedCustomers() {

		return Arrays.asList(
				new Customer("Shalini", "Chennai", 60),
				new Customer("Sneha", "Pune",  73),
				new Customer("Simran", "Bangalore", 37),
				new Customer("Trisha", "Hyderabad", 52),
				new Customer("Shalini", "Chennai", 70),
				new Customer("Abirami", "Bangalore", 48),
				new Customer("Trisha", "Mangalore", 45),
				new Customer("Sneha", "Pune", 62),
				new Customer("Shalini", "Chennai",  50)
				);
	}

	public static void main(String[] args) {

		// get customer list
		List<Customer> unsortedCustomerList = getUnSortedCustomers();

		System.out.println("Before Sorting: Customer list :- \n");
		unsortedCustomerList.stream().forEach(System.out::println);


		System.out.println("\n\nSorted Customer list on multiple fields"
				+ " using Method Reference :- \n");

		// 1. customer Name comparator
		Comparator<Customer> nameComparatorMRef = Comparator
				.comparing(Customer::getCustName);

		// 2. customer City comparator
		Comparator<Customer> cityComparatorMRef = Comparator
				.comparing(Customer::getCustCity);

		// 3. customer Age comparator
		Comparator<Customer> ageComparatorMRef = Comparator
				.comparing(Customer::getCustAge);

		// sorting on multiple fields (3-level) using Method Reference
		List<Customer> sortedCustomerList = unsortedCustomerList
				.stream()
				.sorted(
						nameComparatorMRef // 1st compare Name
						.thenComparing(cityComparatorMRef) // then 2nd compare City
						.thenComparing(ageComparatorMRef)) // then 3rd compare Age
				.collect(Collectors.toList()); // collect sorted customers to new list

		// print new list to console using forEach()
		sortedCustomerList.stream().forEach(System.out::println);
	}
}

Output:

Before Sorting: Customer list :- 

Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Shalini, custCity=Chennai, custAge=50]


Sorted Customer list on multiple fields using Method Reference :- 

Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Shalini, custCity=Chennai, custAge=50]
Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]

2.3 Inline sorting using Comparator

  • In this approach, we are going to pass 3 Comparators to sorted() method using thenComparing() method one-by-one using Method Reference
package net.bench.resources.stream.sorting.multiple.fields;

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

public class CustomerSortingUsingJava8Comparing {

	// customer list
	private static List<Customer> getUnSortedCustomers() {

		return Arrays.asList(
				new Customer("Shalini", "Chennai", 60),
				new Customer("Sneha", "Pune",  73),
				new Customer("Simran", "Bangalore", 37),
				new Customer("Trisha", "Hyderabad", 52),
				new Customer("Shalini", "Chennai", 70),
				new Customer("Abirami", "Bangalore", 48),
				new Customer("Trisha", "Mangalore", 45),
				new Customer("Sneha", "Pune", 62),
				new Customer("Shalini", "Chennai",  50)
				);
	}

	// main() method
	public static void main(String[] args) {

		// get customer list
		List<Customer> unsortedCustomerList = getUnSortedCustomers();

		System.out.println("Before Sorting: Customer list :- \n");
		unsortedCustomerList.stream().forEach(System.out::println);


		System.out.println("\n\nSorted Customer list on multiple fields :- \n");

		// inline - sorting on multiple fields
		List<Customer> sortedCustomerList = unsortedCustomerList
				.stream()
				.sorted(
						Comparator.comparing(Customer::getCustName) // 1st compare Name
						.thenComparing(Customer::getCustCity) // then 2nd compare City
						.thenComparing(Customer::getCustAge)) // then 3rd compare Age
				.collect(Collectors.toList()); // collect sorted customers to new list

		// print new list to console using forEach()
		sortedCustomerList.stream().forEach(System.out::println);
	}
}

Output:

Before Sorting: Customer list :- 

Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Shalini, custCity=Chennai, custAge=50]


Sorted Customer list on multiple fields :- 

Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Shalini, custCity=Chennai, custAge=50]
Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]

2.4 Collections.sort() method

  • In this approach, we are going to define 3 Comparators namely nameComparator, cityComparator and ageComparator using Method Reference
  • Finally, we are going to create another composition Comparator using thenComparing() method passing 3 comparators one-by-one
  • Customer list and composition Comparator are passed as arguments to Collections.sort() method for multiple field sorting
package net.bench.resources.stream.sorting.multiple.fields;

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

public class MultipleSortingUsingCollectionsSortMethod {

	// customer list
	private static List<Customer> getUnSortedCustomers() {

		return Arrays.asList(
				new Customer("Shalini", "Chennai", 60),
				new Customer("Sneha", "Pune",  73),
				new Customer("Simran", "Bangalore", 37),
				new Customer("Trisha", "Hyderabad", 52),
				new Customer("Shalini", "Chennai", 70),
				new Customer("Abirami", "Bangalore", 48),
				new Customer("Trisha", "Mangalore", 45),
				new Customer("Sneha", "Pune", 62),
				new Customer("Shalini", "Chennai",  50)
				);
	}

	public static void main(String[] args) {

		// get customer list
		List<Customer> customerList = getUnSortedCustomers();

		System.out.println("Before Sorting: Customer list :- \n");
		customerList.stream().forEach(System.out::println);


		System.out.println("\n\nSorting Customer list using Collection.sort() :- \n");

		// 1. customer Name comparator
		Comparator<Customer> nameComparator = Comparator
				.comparing(Customer::getCustName);

		// 2. customer City comparator
		Comparator<Customer> cityComparator = Comparator
				.comparing(Customer::getCustCity);

		// 3. customer Age comparator
		Comparator<Customer> ageComparator = Comparator
				.comparing(Customer::getCustAge);

		// 4. composition of above 3 Comparators
		Comparator<Customer> multipleFieldComparator = nameComparator // 1st compare Name
				.thenComparing(cityComparator) // then 2nd compare City
				.thenComparing(ageComparator); // then 3rd compare Age

		// sorting on multiple fields using composition Comparator
		Collections.sort(customerList, multipleFieldComparator);

		// print to console
		customerList.forEach(System.out::println);
	}
}

Output:

Before Sorting: Customer list :- 

Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Shalini, custCity=Chennai, custAge=50]


Sorting Customer list using Collection.sort() :- 

Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Shalini, custCity=Chennai, custAge=50]
Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]

2.5 Arrays.sort() method

  • In this approach, we are going to define 3 Comparators namely nameComparator, cityComparator and ageComparator using Method Reference
  • Finally, we are going to create another composition Comparator using thenComparing() method passing 3 comparators one-by-one
  • Customer[] array and composition Comparator are passed as arguments to Arrays.sort() method for multiple field sorting
  • Note: we can also print Arrays in the following manner Arrays.toString(customerArr) but result will be in one single line
package net.bench.resources.stream.sorting.multiple.fields;

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

public class MultipleSortingUsingArraysSortMethod {

	// customer list
	private static Customer[] getUnSortedCustomers() {

		return new Customer[] {
				new Customer("Shalini", "Chennai", 60),
				new Customer("Sneha", "Pune",  73),
				new Customer("Simran", "Bangalore", 37),
				new Customer("Trisha", "Hyderabad", 52),
				new Customer("Shalini", "Chennai", 70),
				new Customer("Abirami", "Bangalore", 48),
				new Customer("Trisha", "Mangalore", 45),
				new Customer("Sneha", "Pune", 62),
				new Customer("Shalini", "Chennai",  50)
		};
	}

	public static void main(String[] args) {

		// get customer list
		Customer[] customerArr = getUnSortedCustomers();

		System.out.println("Before Sorting: Customer Array :- \n");
		Arrays.stream(customerArr).forEach(System.out::println);


		System.out.println("\n\nSorting Customer[] using Arrays.sort() :- \n");

		// 1. customer Name comparator
		Comparator<Customer> nameComparator = Comparator
				.comparing(Customer::getCustName);

		// 2. customer City comparator
		Comparator<Customer> cityComparator = Comparator
				.comparing(Customer::getCustCity);

		// 3. customer Age comparator
		Comparator<Customer> ageComparator = Comparator
				.comparing(Customer::getCustAge);

		// 4. composition of above 3 Comparators
		Comparator<Customer> multipleFieldComparator = nameComparator // 1st compare Name
				.thenComparing(cityComparator) // then 2nd compare City
				.thenComparing(ageComparator); // then 3rd compare Age

		// sorting on multiple fields using composition Comparator
		Arrays.sort(customerArr, multipleFieldComparator);

		// print to console
		Arrays.stream(customerArr).forEach(System.out::println);
	}
}

Output:

Before Sorting: Customer Array :- 

Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Shalini, custCity=Chennai, custAge=50]


Sorting Customer[] using Arrays.sort() :- 

Customer [custName=Abirami, custCity=Bangalore, custAge=48]
Customer [custName=Shalini, custCity=Chennai, custAge=50]
Customer [custName=Shalini, custCity=Chennai, custAge=60]
Customer [custName=Shalini, custCity=Chennai, custAge=70]
Customer [custName=Simran, custCity=Bangalore, custAge=37]
Customer [custName=Sneha, custCity=Pune, custAge=62]
Customer [custName=Sneha, custCity=Pune, custAge=73]
Customer [custName=Trisha, custCity=Hyderabad, custAge=52]
Customer [custName=Trisha, custCity=Mangalore, custAge=45]

References:

Happy Coding !!
Happy Learning !!

Java 8 – How to Sort HashMap entries by its Keys
Java 8 - How to sort List and Arrays with null values