In this article, we will discuss how to sort list of Objects on multiple field/parameters using static method Comparator.comparing() and default method thenComparingLong()
- Comparing.comparing() method is used to sort any type of key for 1st level sorting
- thenComparingLong() accepts ToLongFunction functional interface which means it is used to sort long-type key for 2nd level sorting
1. thenComparingLong() method :
- Returns a lexicographic-order comparator with a function that extracts a
long
sort key - This default method accepts a function that extracts a long sort key from a type T
- Method signature :-
- default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor)
- Where
- T is the type of element to be compared
- keyExtractor is the function used to extract the long sort key
- Exception :- Throws NullPointerException, if the argument is null
2. thenComparingLong() examples :
2.1 Sort Product list first by Name & then by Quantity
- 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 quantity is of type primitive long
Product.java
package net.bench.resources.comparator.thencomparinglong;
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
}
SortProductListByNameAndThenByQuantity.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
- thenComparingLong() :- then we are going to compare their quantities, if name of the Products are same for 2nd level sorting
- thenComparingLong() method accepts ToLongFunction which means it accepts key of long type only
package net.bench.resources.comparator.thencomparinglong;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortProductListByNameAndThenByQuantity {
// 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 Quantity
System.out.println("\n\nSort Product list"
+ " first by Name & then by Quantity :-\n");
// 2.1 sorting/iterating/printing
products
.stream() // 1. get sequential stream
.sorted(
Comparator.comparing(Product::getName) // 1. name sorting
.thenComparingLong(Product::getQuantity) // 2. long sorting
)
.forEach(product -> System.out.println(
"Product [name=" + product.getName()
+ ", quantity=" + product.getQuantity()
+ ", id=" + product.getId()
+ ", price=" + product.getPrice()
+ "]"
)); // 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 Quantity :-
Product [name=Lentils, quantity=803, id=103, price=102.45]
Product [name=Oil, quantity=303, id=105, price=45.5]
Product [name=Oil, quantity=502, id=102, price=58.19]
Product [name=Wheat, quantity=208, id=104, price=164.75]
Product [name=Wheat, quantity=1089, id=101, price=36.89]
2.2 Sort Student list first by Name & then by Id
- Student class is defined with 3 attributes namely rollNumber, name and their age
- Along with 3 attributes, parameterized constructor, getters/setters and toString() method is defined – removed for brevity
- Member variable rollNumber is of type primitive long
Student.java
package net.bench.resources.comparator.thencomparinglong;
public class Student {
// member variables
private long rollNumber;
private String name;
private int age;
// 3-arg parameterized constructors
// getters & setters
// toString()
}
SortStudentListByNameAndThenByRollNumber.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
- thenComparingLong() :- then we are going to compare their rollNumbers, if name of the Students are same for 2nd level sorting
- thenComparingLong() method accepts ToLongFunction which means it accepts key of long type only
package net.bench.resources.comparator.thencomparinglong;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SortStudentListByNameAndThenByRollNumber {
// List of Students
private static List<Student> getStudentList() {
return Arrays.asList(
new Student(20042033L, "Viraj", 29),
new Student(20042021L, "Krish", 25),
new Student(20042026L, "Rishi", 33),
new Student(20042014L, "Krish", 19),
new Student(20042037L, "Viraj", 34)
);
}
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 RollNumber
System.out.println("\n\nSort Student list"
+ " first by Name & then by RollNumber :-\n");
// 2.1 sorting using Collections.sort() & Comparator
Collections.sort(studentList, // original list
Comparator.comparing(Student::getName) // 1. name sorting
.thenComparingLong(Student::getRollNumber) // 2. long sorting
);
// 2.2 print to console
studentList.forEach(student -> System.out.println(
"Student [name=" + student.getName()
+ ", rollNumber=" + student.getRollNumber()
+ ", age=" + student.getAge()
+ "]"
)); // customized printing
}
}
Output:
Student list as per Insertion-order :-
Student [rollNumber=20042033, name=Viraj, age=29]
Student [rollNumber=20042021, name=Krish, age=25]
Student [rollNumber=20042026, name=Rishi, age=33]
Student [rollNumber=20042014, name=Krish, age=19]
Student [rollNumber=20042037, name=Viraj, age=34]
Sort Student list first by Name & then by RollNumber :-
Student [name=Krish, rollNumber=20042014, age=19]
Student [name=Krish, rollNumber=20042021, age=25]
Student [name=Rishi, rollNumber=20042026, age=33]
Student [name=Viraj, rollNumber=20042033, age=29]
Student [name=Viraj, rollNumber=20042037, age=34]
2.3 Throws NullPointerException if argument is NULL
- If the input argument to thenComparingLong() 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
SortProductListWithNullPresent.java
package net.bench.resources.comparator.thencomparinglong;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortProductListWithNullPresent {
// List of Products
private static List<Product> getProductList() {
return Arrays.asList(
null,
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 Quantity
System.out.println("\n\nSort Product list"
+ " first by Name & then by Quantity :-\n");
// 2.1 sorting/iterating/printing
products
.stream() // 1. get sequential stream
.sorted(
Comparator.comparing(Product::getName) // 1. name sorting
.thenComparingLong(Product::getQuantity) // 2. long sorting
)
.forEach(product -> System.out.println(
"Product [name=" + product.getName()
+ ", quantity=" + product.getQuantity()
+ ", id=" + product.getId()
+ ", price=" + product.getPrice()
+ "]"
)); // customized printing
}
}
Output:
Product list as per Insertion-order :-
null
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 Quantity :-
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:1512)
at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:348)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef
.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at net.bench.resources.comparator.thencomparinglong.SortProductListWithNullPresent
.main(SortProductListWithNullPresent.java:46)
References:
- https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html
- https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#thenComparingLong-java.util.function.ToLongFunction-
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
- https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
- https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html
Happy Coding !!
Happy Learning !!