Java 8 Lambda : Comparator example
In this example, we will show you how to use Java 8 Lambda expression to write a Comparator
to sort a List.
1. Classic Comparator
example.
Comparator<Developer> byName = new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getName().compareTo(o2.getName());
}
};
2. Lambda expression equivalent.
Comparator<Developer> byName =
(Developer o1, Developer o2)->o1.getName().compareTo(o2.getName());
1. Sort without Lambda
Example to compare the Developer
objects using their age. Normally, you use Collections.sort
and pass an anonymous Comparator
class like this :
package com.mkyong.java8;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class TestSorting {
public static void main(String[] args) {
List<Developer> listDevs = getDevelopers();
System.out.println("Before Sort");
for (Developer developer : listDevs) {
System.out.println(developer);
}
//sort by age
Collections.sort(listDevs, new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getAge() - o2.getAge();
}
});
System.out.println("After Sort");
for (Developer developer : listDevs) {
System.out.println(developer);
}
}
private static List<Developer> getDevelopers() {
List<Developer> result = new ArrayList<Developer>();
result.add(new Developer("mkyong", new BigDecimal("70000"), 33));
result.add(new Developer("alvin", new BigDecimal("80000"), 20));
result.add(new Developer("jason", new BigDecimal("100000"), 10));
result.add(new Developer("iris", new BigDecimal("170000"), 55));
return result;
}
}
Output
Before Sort
Developer [name=mkyong, salary=70000, age=33]
Developer [name=alvin, salary=80000, age=20]
Developer [name=jason, salary=100000, age=10]
Developer [name=iris, salary=170000, age=55]
After Sort
Developer [name=jason, salary=100000, age=10]
Developer [name=alvin, salary=80000, age=20]
Developer [name=mkyong, salary=70000, age=33]
Developer [name=iris, salary=170000, age=55]
When the sorting requirement is changed, you just pass in another new anonymous Comparator
class :
//sort by age
Collections.sort(listDevs, new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getAge() - o2.getAge();
}
});
//sort by name
Collections.sort(listDevs, new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getName().compareTo(o2.getName());
}
});
//sort by salary
Collections.sort(listDevs, new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getSalary().compareTo(o2.getSalary());
}
});
It works, but, do you think it is a bit weird to create a class just because you want to change a single line of code?
2. Sort with Lambda
In Java 8, the List
interface is supports the sort
method directly, no need to use Collections.sort
anymore.
//List.sort() since Java 8
listDevs.sort(new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o2.getAge() - o1.getAge();
}
});
Lambda expression example :
package com.mkyong.java8;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class TestSorting {
public static void main(String[] args) {
List<Developer> listDevs = getDevelopers();
System.out.println("Before Sort");
for (Developer developer : listDevs) {
System.out.println(developer);
}
System.out.println("After Sort");
//lambda here!
listDevs.sort((Developer o1, Developer o2)->o1.getAge()-o2.getAge());
//java 8 only, lambda also, to print the List
listDevs.forEach((developer)->System.out.println(developer));
}
private static List<Developer> getDevelopers() {
List<Developer> result = new ArrayList<Developer>();
result.add(new Developer("mkyong", new BigDecimal("70000"), 33));
result.add(new Developer("alvin", new BigDecimal("80000"), 20));
result.add(new Developer("jason", new BigDecimal("100000"), 10));
result.add(new Developer("iris", new BigDecimal("170000"), 55));
return result;
}
}
Output
Before Sort
Developer [name=mkyong, salary=70000, age=33]
Developer [name=alvin, salary=80000, age=20]
Developer [name=jason, salary=100000, age=10]
Developer [name=iris, salary=170000, age=55]
After Sort
Developer [name=jason, salary=100000, age=10]
Developer [name=alvin, salary=80000, age=20]
Developer [name=mkyong, salary=70000, age=33]
Developer [name=iris, salary=170000, age=55]
3. More Lambda Examples
3.1 Sort By age
//sort by age
Collections.sort(listDevs, new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getAge() - o2.getAge();
}
});
//lambda
listDevs.sort((Developer o1, Developer o2)->o1.getAge()-o2.getAge());
//lambda, valid, parameter type is optional
listDevs.sort((o1, o2)->o1.getAge()-o2.getAge());
3.2 Sort by name
//sort by name
Collections.sort(listDevs, new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getName().compareTo(o2.getName());
}
});
//lambda
listDevs.sort((Developer o1, Developer o2)->o1.getName().compareTo(o2.getName()));
//lambda
listDevs.sort((o1, o2)->o1.getName().compareTo(o2.getName()));
3.3 Sort by salary
//sort by salary
Collections.sort(listDevs, new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o1.getSalary().compareTo(o2.getSalary());
}
});
//lambda
listDevs.sort((Developer o1, Developer o2)->o1.getSalary().compareTo(o2.getSalary()));
//lambda
listDevs.sort((o1, o2)->o1.getSalary().compareTo(o2.getSalary()));
3.4 Reversed sorting.
3.4.1 Lambda expression to sort a List using their salary.
Comparator<Developer> salaryComparator = (o1, o2)->o1.getSalary().compareTo(o2.getSalary());
listDevs.sort(salaryComparator);
Output
Developer [name=mkyong, salary=70000, age=33]
Developer [name=alvin, salary=80000, age=20]
Developer [name=jason, salary=100000, age=10]
Developer [name=iris, salary=170000, age=55]
3.4.2 Lambda expression to sort a List using their salary, reversed order.
Comparator<Developer> salaryComparator = (o1, o2)->o1.getSalary().compareTo(o2.getSalary());
listDevs.sort(salaryComparator.reversed());
Output
Developer [name=iris, salary=170000, age=55]
Developer [name=jason, salary=100000, age=10]
Developer [name=alvin, salary=80000, age=20]
Developer [name=mkyong, salary=70000, age=33]
Hi,
In Java 8 you could print the list of developers like this :
listDevs.forEach(System.out::println);
Instead of :
listDevs.forEach((developer)->System.out.println(developer));
Romain.
i could format my output like below say if my list is “Integers” (list having 100,10,222,3000,40000)
i can use
listInts.forEach((i)->System.out.println(i+”,”));
using method references all integers will be appended and displayed, but can i use “,” as above using method references
?? – any idea
Nope!
Thanks for the “method references” example.
what if there is a null value? These examples is not handling null scenarios.
You may want to convert it to empty string by StringUtils before comparison or capture the exception in the wrapper code.
humans.sort((h1, h2) -> {
if (h1 == null) {
return h2 == null ? 0 : 1;
}
else if (h2 == null) {
return -1;
}
return h1.getName().compareTo(h2.getName());
});
from where we will get Develpoer class?
I am getting exception “Developer cannot be resolved to a type”.
package com.avi.lamda;
import java.math.BigDecimal;
public class Developer {
private String name;
private BigDecimal salary;
private int age;
public Developer(String name, BigDecimal salary, int age) {
this.name=name;
this.salary=salary;
this.age=age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return name+” “+salary+” “+age;
}
}
Keeping data members private and trying to use comparator (lambda or otherwise) is not going to work as it won’t be able to access the private field. Either make them public or default, or implement Comparable and override compareTo.
it works with private too!!
Hi Mkyong, thanks for this article. You explained it very well
The lambda comparator example can be simplified slightly by omitting the class declaration:
Comparator byName =
(o1, o2)->o1.getName().compareTo(o2.getName());
Very good explaination, simple and straight farward! Thanks
very good 🙂
I love this color scheme fo idea intellij. What is the name of it?
Sempre mandando muito!!!! Valeu Mkyong!!!
Hi Mkyong, We can sort getAge max to min??
I did not find my comment.
Hi Mkyong,
Can we sort multiple fields at a time using lambdas, if it is please share me the example.
Below code is also use for sorting
Collections.sort(developerList, Comparator.comparing(Developer::getAge));
Sorry brother i mean classes are not properly organize missed dependency class file in some of your articles. You article are great, but if you can organize the java code in proper place it would be great. Thank you so much for sharing.
not properly organize missed dependency file. You article is good but Please post in organize manager
User below code
Thread t = new Thread(() -> System.out.println());
t.start();
Is it possible to have the complete list of files by link? Because following your tutorial I have a lot of problem, thanks
Well Explained!
very nice thanks
awesome post….thank you soo much
nice article and example is also very clear and simple
thank you for this awesome post
I am not able get the output as mentioned here (sorting with out lambada)
I have complied and executed above program in eclipse mar and the output is
Before Sort
javatpointegs.Comparatoreg$Developer@15db9742
javatpointegs.Comparatoreg$Developer@6d06d69c
javatpointegs.Comparatoreg$Developer@7852e922
javatpointegs.Comparatoreg$Developer@4e25154f
After Sort
javatpointegs.Comparatoreg$Developer@15db9742
javatpointegs.Comparatoreg$Developer@6d06d69c
javatpointegs.Comparatoreg$Developer@7852e922
javatpointegs.Comparatoreg$Developer@4e25154f
this can happen if you do not override toString() method in Developer class.
I find that I keep coming back here, because your Java 8 examples are the best. You keep it simple and focused, much more so than the other examples out there.
Got me too long to find information like this on other sites until I reached this article. Thanks, very informative 🙂
Here Lambda expression can be used to implement comparator because Comparator is a Functional Interface. Lambda expression provides implementation of the functional interface.
See some of the Lambda expression examples here – http://netjs.blogspot.in/2015/06/lambda-expression-examples-in-java-8.html
Read about functional interface here – http://netjs.blogspot.in/2015/06/functional-interfaces-and-lambda-expression-in-java-8.html
Actually, we can do it even simplier. Instead of writing for example
Comparator salaryComparator = (o1, o2)->o1.getSalary().compareTo(o2.getSalary());
listDevs.sort(salaryComparator.reversed());
you can shorten this using “comparing” factory method combined with method reference:
listDevs.sort(Comparator.comparing(Developer::getSalary()).reversed());
after static import:
listDevs.sort(comparing(Developer::getSalary()).reversed());
Thanks for your example, The “()” from getSalary() will prompts error, just remove it.
listDevs.sort(Comparator.comparing(Developer::getSalary));
how I’m gonna reach the sub attribute of Salary in case of Salary is another class?
Yes of course, I have meant method reference, not a method call, there. Sorry for mistake.
Thanks.. Very good info on Comparator.comparing !
nice article
very clear
thanks mkyong for this article,
java projects source code .
nice one post myyong and visit also java8 program examples
nice