Java 8 – Comparator.thenComparingDouble() method

In this article, we will discuss how to sort list of Objects on multiple field/parameters using static method Comparator.comparing() and default method thenComparingDouble()

  • Comparing.comparing() method is used to sort any type of key for 1st level sorting
  • thenComparingDouble() accepts ToDoubleFunction functional interface which means it is used to sort double-type key for 2nd level sorting

1. thenComparingDouble() method :

  • Returns a lexicographic-order comparator with a function that extractsdouble sort key
  • This default method accepts a function that extracts a double sort key from a type T
  • Method signature :-
    • default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor)
  • Where
    • T is the type of element to be compared
    • keyExtractor is the function used to extract the double sort key
  • Exception :- Throws NullPointerException, if the argument is null

2. thenComparingDouble() examples :

2.1 Sort Product list first by Name & then by Price

  • Product class is defined with 4 attributes namely id, name, quantity and their price
  • Along with 4 attributes, parameterized constructor, getters/setters and toString() method is defined – removed for brevity
  • Member variable price is of type primitive double

Product.java

package net.bench.resources.comparator.thencomparingdouble;

public class Product {

	// member variables
	private int id;
	private String name;
	private long quantity;
	private double price;

	// 4-arg parameterized constructor

	// getters and setters

	// toString() method
}

SortProductListByNameAndThenByPrice.java

  • A list contains Product information for 5 as per insertion-order with some product names are same
  • 2-level attribute Sorting :-
    • Comparator.comparing() :- we are going to sort the Product list according to alphabetial order of its name for the 1st level sorting
    • thenComparingDouble() :- then we are going to compare their prices, if name of the Products are same for 2nd level sorting
  • thenComparingDouble() method accepts ToDoubleFunction which means it accepts key of double type only
package net.bench.resources.comparator.thencomparingdouble;

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

public class SortProductListByNameAndThenByPrice {

	// List of Products
	private static List<Product> getProductList() {

		return Arrays.asList(
				new Product(101, "Wheat", 1089L, 36.89),
				new Product(102, "Oil", 502L, 58.19),
				new Product(103, "Lentils", 803L, 102.45),
				new Product(104, "Wheat", 208L, 164.75),
				new Product(105, "Oil", 303L, 45.50)
				);
	}

	public static void main(String[] args) {

		// 1. get Product list
		List<Product> products = getProductList();


		// 1.1 print to console
		System.out.println("Product list as per Insertion-order :-\n");
		products.forEach(System.out::println); // iterate/printing



		// 2. Sort Product list first by Name & then by Price
		System.out.println("\n\nSort Product list"
				+ " first by Name & then by Price :-\n");


		// 2.1 sorting/iterating/printing
		products
		.stream() // 1. get sequential stream
		.sorted(
				Comparator.comparing(Product::getName) // 1. name sorting
				.thenComparingDouble(Product::getPrice) // 2. double sorting
				)
		.forEach(product -> System.out.println(
				"Product [name=" + product.getName()
				+ ", price=" + product.getPrice() 
				+ ", id=" + product.getId()
				+ ", quantity=" + product.getQuantity()
				+ "]"
				)); // customized printing
	}
}

Output:

Product list as per Insertion-order :-

Product [id=101, name=Wheat, quantity=1089, price=36.89]
Product [id=102, name=Oil, quantity=502, price=58.19]
Product [id=103, name=Lentils, quantity=803, price=102.45]
Product [id=104, name=Wheat, quantity=208, price=164.75]
Product [id=105, name=Oil, quantity=303, price=45.5]


Sort Product list first by Name & then by Price :-

Product [name=Lentils, price=102.45, id=103, quantity=803]
Product [name=Oil, price=45.5, id=105, quantity=303]
Product [name=Oil, price=58.19, id=102, quantity=502]
Product [name=Wheat, price=36.89, id=101, quantity=1089]
Product [name=Wheat, price=164.75, id=104, quantity=208]

2.2 Sort Student list first by Name & then by Percentage

  • Student class is defined with 3 attributes namely id, name and their percentage
  • Along with 3 attributes, parameterized constructor, getters/setters and toString() method is defined – removed for brevity
  • Member variable percanatge is of type primitive double

Student.java

package net.bench.resources.comparator.thencomparingdouble;

public class Student {

	// member variables
	private int rollNumber;
	private String name;
	private double percentage;

	// 3-arg parameterized constructors

	// getters & setters

	// toString()
}

SortStudentListByNameAndThenByPercentage.java

  • A list contains Student information for 5 as per insertion-order with few students having same names
  • 2-level attribute Sorting :-
    • Comparator.comparing() :- we are going to sort the Student list according to alphabetial order of its name for the 1st level sorting
    • thenComparingDouble() :- then we are going to compare their percentages, if name of the Students are same for 2nd level sorting
  • thenComparingDouble() method accepts ToDoubleFunction which means it accepts key of double type only
package net.bench.resources.comparator.thencomparingdouble;

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

public class SortStudentListByNameAndThenByPercentage {

	// List of Students
	private static List<Student> getStudentList() {

		return Arrays.asList(

				new Student(2033, "Viraj", 65.67),
				new Student(2020, "Krish", 91.97),
				new Student(2004, "Rishi", 78.13),
				new Student(2015, "Krish", 35.32),
				new Student(2037, "Viraj", 51.02)
				);
	}

	public static void main(String[] args) {

		// 1. get Student list
		List<Student> studentList = getStudentList();


		// 1.1 print to console
		System.out.println("Student list as per Insertion-order :-\n");
		studentList.forEach(System.out::println); // iterating/printing



		// 2. Sort Student list first by Name & then by Percentage
		System.out.println("\n\nSort Student list"
				+ " first by Name & then by Percentage :-\n");


		// 2.1 sorting using Collections.sort() & Comparator
		Collections.sort(studentList, // original list
				Comparator.comparing(Student::getName) // 1. name sorting
				.thenComparingDouble(Student::getPercentage) // 2. double sorting
				);


		// 2.2 print to console
		studentList.forEach(student -> System.out.println(
				"Student [name=" + student.getName()
				+ ", percentage=" + student.getPercentage() 
				+ ", rollNumber=" + student.getRollNumber() 
				+ "]"
				)); // customized printing
	}
}

Output:

Student list as per Insertion-order :-

Student [rollNumber=2033, name=Viraj, percentage=65.67]
Student [rollNumber=2020, name=Krish, percentage=91.97]
Student [rollNumber=2004, name=Rishi, percentage=78.13]
Student [rollNumber=2015, name=Krish, percentage=35.32]
Student [rollNumber=2037, name=Viraj, percentage=51.02]


Sort Student list first by Name & then by Percentage :-

Student [name=Krish, percentage=35.32, rollNumber=2015]
Student [name=Krish, percentage=91.97, rollNumber=2020]
Student [name=Rishi, percentage=78.13, rollNumber=2004]
Student [name=Viraj, percentage=51.02, rollNumber=2037]
Student [name=Viraj, percentage=65.67, rollNumber=2033]

2.3 Throws NullPointerException if argument is NULL

  • If the input argument to thenComparingDouble() method is null then it throws NullPointerException as shown in the below illustration
  • Check How to sort List and Arrays with null values to handle list with null values while sorting

SortStudentListWithNullPresent.java

package net.bench.resources.comparator.thencomparingdouble;

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

public class SortStudentListWithNullPresent {

	// List of Students
	private static List<Student> getStudentList() {

		return Arrays.asList(
				null,
				new Student(2033, "Viraj", 65.67),
				new Student(2020, "Krish", 91.97),
				new Student(2004, "Rishi", 78.13),
				new Student(2015, "Krish", 35.32),
				new Student(2037, "Viraj", 51.02)
				);
	}

	public static void main(String[] args) {

		// 1. get Student list
		List<Student> studentList = getStudentList();


		// 1.1 print to console
		System.out.println("Student list as per Insertion-order :-\n");
		studentList.forEach(System.out::println); // iterating/printing



		// 2. Sort Student list first by Name & then by Percentage
		System.out.println("\n\nSort Student list"
				+ " first by Name & then by Percentage :-\n");


		// 2.1 sorting using Collections.sort() & Comparator
		Collections.sort(studentList, // original list
				Comparator.comparing(Student::getName) // 1. name sorting
				.thenComparingDouble(Student::getPercentage) // 2. double sorting
				);


		// 2.2 print to console
		studentList.forEach(student -> System.out.println(
				"Student [name=" + student.getName()
				+ ", percentage=" + student.getPercentage() 
				+ ", rollNumber=" + student.getRollNumber() 
				+ "]"
				)); // customized printing
	}
}

Output:

Student list as per Insertion-order :-

null
Student [rollNumber=2033, name=Viraj, percentage=65.67]
Student [rollNumber=2020, name=Krish, percentage=91.97]
Student [rollNumber=2004, name=Rishi, percentage=78.13]
Student [rollNumber=2015, name=Krish, percentage=35.32]
Student [rollNumber=2037, name=Viraj, percentage=51.02]


Sort Student list first by Name & then by Percentage :-

Exception in thread "main" java.lang.NullPointerException
	at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
	at java.util.Comparator.lambda$thenComparing$36697e65$1(Comparator.java:216)
	at java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
	at java.util.TimSort.sort(TimSort.java:220)
	at java.util.Arrays.sort(Arrays.java:1438)
	at java.util.Arrays$ArrayList.sort(Arrays.java:3895)
	at java.util.Collections.sort(Collections.java:175)
	at net.bench.resources.comparator.thencomparingdouble.SortStudentListWithNullPresent
.main(SortStudentListWithNullPresent.java:41)

References:

Happy Coding !!
Happy Learning !!

Java 8 – Iterating HashMap in 8 ways
Java 8 – Comparator.thenComparingLong() method