1. Overview
In this tutorial, We'll learn how to use the Comparator interface in java.
A comparator interface is used to order the user-defined object in sorted order. This comparator interface has the capability to compare the same type of objects.
Comparator is used to sort the object in ascending or descending order.
We will write the example programs on custom objects with a single field or property.
And also how to sort the collection such as a list or set by multiple properties.
2. Comparator Interface
The comparator interface is enriched with new methods in java 8. But before java 8, Comparator has only two methods abstract methods those are compare() and equals() methods.
Syntax
int compare(T o1, T o2) boolean equals(Object obj)
3. Comparator Methods
Below are the methods that are added in JDK 1.8 and above. Some of them are static and default.
static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)
Accepts a function that extracts a Comparable sort key from a type T, and returns a Comparator<T> that compares by that sort key.
static <T,U> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
Accepts a function that extracts a sort key from a type T, and returns a Comparator<T> that compares by that sort key using the specified Comparator.
static <T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor)
Accepts a function that extracts a double sort key from a type T, and returns a Comparator<T> that compares by that sort key.
static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor)
Accepts a function that extracts an int sort key from a type T, and returns a Comparator<T> that compares by that sort key.
static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor)
Accepts a function that extracts a long sort key from a type T, and returns a Comparator<T> that compares by that sort key.
static <T extends Comparable<? super T>> Comparator<T> naturalOrder()
Returns a comparator that compares Comparable objects in natural order.
static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)
Returns a null-friendly comparator that considers null to be less than non-null.
static <T> Comparator<T> nullsLast(Comparator<? super T> comparator)
Returns a null-friendly comparator that considers null to be greater than non-null.
default Comparator<T> reversed()
Returns a comparator that imposes the reverse ordering of this comparator.
static <T extends Comparable<? super T>> Comparator<T> reverseOrder()
Returns a comparator that imposes the reverse of the natural ordering.
default Comparator<T> thenComparing(Comparator<? super T> other)
Returns a lexicographic-order comparator with another comparator.
default <U extends Comparable<? super U>> Comparator<T> thenComparing(Function<? super T,? extends U> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts a Comparable sort key.
default <U> Comparator<T> thenComparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
Returns a lexicographic-order comparator with a function that extracts a key to be compared with the given Comparator.
default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts a double sort key.
default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts a int sort key.
default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor)
Returns a lexicographic-order comparator with a function that extracts a long sort key.
4. Compartor Sorting With Single Property or Field
Let us create the custom class Teacher with the properties name, subject, experience. Add the teacher objects to the List. Now we want to sort the list by teacher name.
This can be solved in two ways.
A) By writing our own custom sorting logic to sort it by teacher name.
B) By using comparator interface: This interface is having the compare() method. This is used to order the same type of objects by a specific field. In our case, it is by teacher name.
Next, we need to pass the custom comparator to the Collections.sort() method as below.
Collections.sort(list, customComparator);
How does Collections.sort() method work in java?
Internally, Collections.sort() method calls compare() method of custom comparator class. This compare() method logic gets executed. This method returns integer values such as positive or negative or zero. The returned value is used to swap the objects.
Let us write the full comparator example code to sort by one field.
The below example sorts the list of teacher objects by the subject they teach.
Example
package com.javaprogramto.java8.comparator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class ComparatorExample { public static void main(String[] args) { List<Teacher> teachers = new ArrayList<>(); teachers.add(new Teacher("Rajesh", "Science", 10)); teachers.add(new Teacher("Mahesh", "Mathematics", 5)); teachers.add(new Teacher("Suresh", "English", 10)); teachers.add(new Teacher("Rakesh", "Science", 3)); teachers.add(new Teacher("Ramesh", "Mathematics", 8)); System.out.println("Teachers object before sorting"); teachers.forEach(teacher -> System.out.println("Teacher name - " + teacher.getName() + ", subject - " + teacher.getSubject() + ", exp - " + teacher.getExperience())); Collections.sort(teachers, new SubjectComparator()); System.out.println("\nTeachers object after sorting"); teachers.forEach(teacher -> System.out.println("Teacher name - " + teacher.getName() + ", subject - " + teacher.getSubject() + ", exp - " + teacher.getExperience())); } } // Custom comparator to sort Teacher objects by subject they teach class SubjectComparator implements Comparator<Teacher> { @Override public int compare(Teacher t1, Teacher t2) { return t1.getSubject().compareTo(t2.getSubject()); } } class Teacher { String name; String subject; int experience; public Teacher(String name, String subject, int experience) { super(); this.name = name; this.subject = subject; this.experience = experience; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public int getExperience() { return experience; } public void setExperience(int experience) { this.experience = experience; } }
Output
Teachers object before sorting Teacher name - Rajesh, subject - Science, exp - 10 Teacher name - Mahesh, subject - Mathematics, exp - 5 Teacher name - Suresh, subject - English, exp - 10 Teacher name - Rakesh, subject - Science, exp - 3 Teacher name - Ramesh, subject - Mathematics, exp - 8 Teachers object before sorting Teacher name - Suresh, subject - English, exp - 10 Teacher name - Mahesh, subject - Mathematics, exp - 5 Teacher name - Ramesh, subject - Mathematics, exp - 8 Teacher name - Rajesh, subject - Science, exp - 10 Teacher name - Rakesh, subject - Science, exp - 3
4. Compartor Sorting With more than one field
As of now, we have seen the custom sorting based on the one field of teacher class.
The above section output is sorted by the natural order of the subject field and you could see the same subject is taught by two teachers. But those teachers differ in their experience. In such cases, we may not get the teachers objects in the proper order.
The actual order is sorted by subject and their experience in ascending order.
To get this output, we need to another field to the existing sorting logic within the custom comparator.
Look at the below comparator with multiple fields for sorting on subject and experience fields.
Example program to sort by multiple fields with a comparator interface
package com.javaprogramto.java8.comparator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class ComparatorExample2 { public static void main(String[] args) { List<Teacher> teachers = new ArrayList<>(); teachers.add(new Teacher("Rajesh", "Science", 10)); teachers.add(new Teacher("Mahesh", "Mathematics", 5)); teachers.add(new Teacher("Suresh", "English", 10)); teachers.add(new Teacher("Rakesh", "Science", 3)); teachers.add(new Teacher("Ramesh", "Mathematics", 8)); System.out.println("Teachers object before sorting"); teachers.forEach(teacher -> System.out.println("Teacher name - " + teacher.getName() + ", subject - " + teacher.getSubject() + ", exp - " + teacher.getExperience())); Collections.sort(teachers, new SubjectExperienceComparator()); System.out.println("\nTeachers object before sorting"); teachers.forEach(teacher -> System.out.println("Teacher name - " + teacher.getName() + ", subject - " + teacher.getSubject() + ", exp - " + teacher.getExperience())); } } // Custom comparator to sort Teacher objects by subject they teach and their experience level class SubjectExperienceComparator implements Comparator<Teacher> { @Override public int compare(Teacher t1, Teacher t2) { int name = t1.getSubject().compareTo(t2.getSubject()); int exp = Integer.valueOf(t1.getExperience()).compareTo(t2.getExperience()); return name == 0 ? exp : name; } }
Output
Teachers object before sorting Teacher name - Rajesh, subject - Science, exp - 10 Teacher name - Mahesh, subject - Mathematics, exp - 5 Teacher name - Suresh, subject - English, exp - 10 Teacher name - Rakesh, subject - Science, exp - 3 Teacher name - Ramesh, subject - Mathematics, exp - 8 Teachers object before sorting Teacher name - Suresh, subject - English, exp - 10 Teacher name - Mahesh, subject - Mathematics, exp - 5 Teacher name - Ramesh, subject - Mathematics, exp - 8 Teacher name - Rakesh, subject - Science, exp - 3 Teacher name - Rajesh, subject - Science, exp - 10
5. Java 8 - Comparator sorting by a single field
In java 8, a Comparator can be created with the help of lambda expressions.
5.1 Using Collections.sort()
In the below example, SubjectCompartor is created by using a lambda statement. This can be passed to the Collections.sort() method.
Example
Comparator<Teacher> subjectComparator = (t1, t2) -> t1.getSubject().compareTo(t2.getSubject()); Collections.sort(teachers, subjectComparator);
5.2 Using Comparator.comparing()
Comparator interface has comparing() method which is a static method. comparing() method is used to create the custom comparator and can be passed to the Collections.sort() method.
We have passed the method reference to the comparing() method.
Example
Comparator<Teacher> subjectComparator = Comparator.comparing(Teacher::getSubject); Collections.sort(teachers, subjectComparator);
5.3 Using Stream.sort()
Java 8 Stream API has sort() method which takes the custom comparator for soring the stream of objects.
Create the comparator with lambda or method ref and then pass it to the sorted() method of the stream.
Example
Comparator<Teacher> subjectComparator1 = Comparator.comparing(Teacher::getSubject); List<Teacher> sortedList1 = teachers.stream().sorted(subjectComparator1).collect(Collectors.toList()); Comparator<Teacher> subjectComparator2 = (t1, t2) -> t1.getSubject().compareTo(t2.getSubject()); List<Teacher> sortedList2 = teachers.stream().sorted(subjectComparator2).collect(Collectors.toList());
6. Java 8 - Comparator sorting by multiple fields
More than one field-based sorting can be easily done by using java 8 concepts.
We can use a custom comparator created by any way that can be used with the stream.sorted() or Collections.sort() method.
To add sort by multiple properties with Collections.comparing() method, you need to use thenComparing() method to add additional fields to Comparator. Like this, you can call thenComparint() method multiple times on base comparor as chain.
Look at the below example that covers all possible combinations.
Example
// using streams.sort // way 1 - comparator with method ref and comparing() and thenComparing() method. Comparator<Teacher> subjectExpComparator1 = Comparator.comparing(Teacher::getSubject) .thenComparing(Teacher::getExperience); List<Teacher> sortedList1 = teachers.stream().sorted(subjectExpComparator1).collect(Collectors.toList()); // way 2 - lambda with comparator Comparator<Teacher> subjectExpComparator2 = (t1, t2) -> { int subjectCompare = t1.getSubject().compareTo(t2.getSubject()); int expCompare = Integer.valueOf(t1.getExperience()).compareTo(t2.getExperience()); return subjectCompare == 0 ? expCompare : subjectCompare; }; List<Teacher> sortedList2 = teachers.stream().sorted(subjectExpComparator1).collect(Collectors.toList()); // way 3 - with anonymous comparator Comparator<Teacher> subjectExpComparator3 = new Comparator<Teacher>() { @Override public int compare(Teacher o1, Teacher o2) { int subjectCompare = t1.getSubject().compareTo(t2.getSubject()); int expCompare = Integer.valueOf(t1.getExperience()).compareTo(t2.getExperience()); return subjectCompare == 0 ? expCompare : subjectCompare; } }; List<Teacher> sortedList3 = teachers.stream().sorted(subjectExpComparator3).collect(Collectors.toList()); // using collections.sort Collections.sort(teachers, subjectExpComparator1); Collections.sort(teachers, subjectExpComparator2); Collections.sort(teachers, subjectExpComparator3);
All examples shown in java 8 produce the same output as with before java 8 versions.
7. Conclusion
In this article, We've seen an in-depth comparator interface in java and java 8 methods.
We've seen examples to sort the custom objects by single field and two or more fields with a comparator with java 8 streams.
No comments:
Post a Comment
Please do not add any spam links in the comments section.