Introduction to the
In this tutorial, we’ll first look at Lambda support in Java 8, and specifically how to use it to write comparators and sort collections.
First, let’s define a simple entity class:
public class Human {
private String name;
private int age;
}
Copy the code
A simple sort of List
Prior to Java 8, sorting a collection would involve creating anonymous inner classes for the comparators used in sorting:
new Comparator<Human>() {
@Override
public int compare(Human h1, Human h2) {
returnh1.getName().compareTo(h2.getName()); }}Copy the code
This one is easier. Let me look at the unit test example:
@Test
public void givenPreLambda() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 10),
new Human("Jack", 12)); Collections.sort(humans, new Comparator<Human>() { @Override public int compare(Human h1, Human h2) {returnh1.getName().compareTo(h2.getName()); }}); Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
Use of Lambda in sorting
With the introduction of Lambdas, we can now bypass anonymous inner classes and achieve the same result with a simple, functional semantic implementation:
(final Human h1, final Human h2) -> h1.getName().compareTo(h2.getName());
Copy the code
Again, we can use the previous test case:
@Test
public void test() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 10),
new Human("Jack", 12)); humans.sort( (Human h1, Human h2) -> h1.getName().compareTo(h2.getName())); assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
Note that we also used the new sorting API for java.util.List added to Java 8, rather than the old collections.sort API.
Sort without type definition
We can further simplify the expression by not specifying a type definition – the compiler can infer this for itself:
(h1, h2) -> h1.getName().compareTo(h2.getName())
Copy the code
For example:
@Test
public void test() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 10),
new Human("Jack", 12)); humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName())); assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
This benefits from Lambda’s method support, which makes my code much cleaner.
Sort using static methods
Next, we will use Lambda Expression to perform the sort and reference static methods.
First, we define the compareByNameThenAge method to return exactly the same value as the compare method in the Comparator
object:
public static int compareByNameThenAge(Human lhs, Human rhs) {
if (lhs.name.equals(rhs.name)) {
return lhs.age - rhs.age;
} else {
returnlhs.name.compareTo(rhs.name); }}Copy the code
Now, how do we use it
humans.sort(Human::compareByNameThenAge);
Copy the code
Take a look at unit tests
@Test
public void test() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 10),
new Human("Jack", 12)); humans.sort(Human::compareByNameThenAge); Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
Sort the internal API
We can also sort comparisons by using a combination of the Collections reference and the Comparator.comparing methods.
We’ll use getName() to build the Lambda expression and sort the List by name:
@Test
public void test() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 10),
new Human("Jack", 12)); Collections.sort( humans, Comparator.comparing(Human::getName)); assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
The reverse order
Java 8 also introduces a helper method for reversing the comparator, which we can quickly use to reverse our sort:
@Test
public void test() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 10),
new Human("Jack", 12)); Comparator<Human> comparator = (h1, h2) -> h1.getName().compareTo(h2.getName()); humans.sort(comparator.reversed()); Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));
}
Copy the code
Multiconditional sort
Comparing lambda expressions is not necessarily very simple, and we can write more complex expressions. For example, sort comparison by name and age.
@Test
public void test() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 12),
new Human("Sarah", 10),
new Human("Zack", 12)); humans.sort((lhs, rhs) -> {if (lhs.getName().equals(rhs.getName())) {
return lhs.getAge() - rhs.getAge();
} else {
returnlhs.getName().compareTo(rhs.getName()); }}); Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));
}
Copy the code
Multi – condition combination sort
The same example can be implemented with new combinatorial support for comparators.
Starting with JDK 8, we can now combine multiple comparators to build more complex comparison logic:
@Test
public void test() {
List<Human> humans = Lists.newArrayList(
new Human("Sarah", 12),
new Human("Sarah", 10),
new Human("Zack", 12)); humans.sort( Comparator.comparing(Human::getName).thenComparing(Human::getAge) ); Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));
}
Copy the code
The Stream order
We can also sort collections using Java 8’s Stream sorted() API.
We can sort streams using natural sort and the sort provided by the comparator. To do this, we have sorted(), which has two corresponding apis:
- Sorted (); To use sorting to sort the elements of a Stream, the element class must implement the Comparable interface
- sorted(Comparator
comparator); Sort elements according to the Comparator instance
Let’s look at an example of how to use the sorted() method of natural sorting:
@Test
public final void test() {
List<String> letters = Lists.newArrayList("B"."A"."C");
List<String> sortedLetters = letters.stream().sorted().collect(Collectors.toList());
assertThat(sortedLetters.get(0), equalTo("A"));
}
Copy the code
Now let’s see how we use a custom Comparator with sorted() :
@Test
public final void test() {
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
Comparator<Human> nameComparator = (h1, h2) -> h1.getName().compareTo(h2.getName());
List<Human> sortedHumans = humans.stream().sorted(nameComparator).collect(Collectors.toList());
assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
If we use the Comparator.comparing() method, we can further simplify the above example:
@Test
public final void test() {
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
List<Human> sortedHumans = humans.stream()
.sorted(Comparator.comparing(Human::getName))
.collect(Collectors.toList());
assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
Stream reverse sort
We can also use stream.sorted () to reverse sort the List.
First, let’s look at an example of how to combine the sorted() method with comparator.reverseorder () to sort a list in reverseOrder:
@Test
public final void test() {
List<String> letters = Lists.newArrayList("B"."A"."C");
List<String> reverseSortedLetters = letters.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
assertThat(reverseSortedLetters.get(0), equalTo("C"));
}
Copy the code
Now, let’s see how to use the sorted() method with a custom Comparator:
@Test
public final void test() {
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
Comparator<Human> reverseNameComparator = (h1, h2) -> h2.getName().compareTo(h1.getName());
List<Human> reverseSortedHumans = humans.stream().sorted(reverseNameComparator)
.collect(Collectors.toList());
assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10)));
}
Copy the code
Finally, let’s simplify the example using the Comparator.comparing() method:
@Test
public final void test() {
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
List<Human> reverseSortedHumans = humans.stream()
.sorted(Comparator.comparing(Human::getName, Comparator.reverseOrder()))
.collect(Collectors.toList());
assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10)));
}
Copy the code
conclusion
The use of Java 8 Lambda expressions to sort lists is very useful and is one of the scenarios where Lambda is used, demonstrating the semantic power of Lambda.