1, an overview of the
In this tutorial, we’ll take a look at Lambda expressions in the upcoming JDK 8 — specifically, how to use them to write comparators and sort collections.
This article is part of the “Java — Back to Basic” series on Baeldung.
First, let’s define a simple entity class:
public class Human {
private String name;
private int age;
public Human() {
super();
}
public Human(final String name, final int age) {
super();
this.name = name;
this.age = age;
}
// standard getters and setters
}
Copy the code
2. Do not use basic ordering of Lambda expressions
Before Java 8, sorting a collection created an anonymous inner class for the Comparator to sort:
new Comparator<Human>() {
@Override
public int compare(Human h1, Human h2) {
returnh1.getName().compareTo(h2.getName()); }}Copy the code
Simply use it to sort the list of Human entities:
@Test
public void givenPreLambda_whenSortingEntitiesByName_thenCorrectlySorted() {
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
3. Use basic ordering of Lambda expressions
According to the introduction of Lambda expressions, we can now get the same result using simple, practical semantics without using anonymous inner classes.
(final Human h1, final Human h2) -> h1.getName().compareTo(h2.getName());
Copy the code
Similarly, we can now test its behavior as before:
@Test
public void whenSortingEntitiesByName_thenCorrectlySorted() {
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
humans.sort((Human h1, Human h2) -> h1.getName().compareTo(h2.getName()));
Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
Note: We also use the new sort API, which was added to java.util.List in Java 8 — not the old collections.sort API.
There is no basic sorting of Type Definitions
We further simplify the expression by not specifying a type definition — the compiler can make its own type judgments:
(h1, h2) -> h1.getName().compareTo(h2.getName())
Copy the code
The tests are still very similar:
@Test
public void givenLambdaShortForm_whenSortingEntitiesByName_thenCorrectlySorted() {
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName()));
Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
5. Sort using references to static methods
Next we’ll use Lambda expressions with static method references to sort.
First, we define the compareByNameThenAge method, which has the exact same signature as the compareTo 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, we’ll use this reference to call the humans.sort method:
humans.sort(Human::compareByNameThenAge);
Copy the code
The end result is a valid sorting collection that uses static methods as comparators:
@Test
public void givenMethodDefinition_whenSortingEntitiesByNameThenAge_thenCorrectlySorted() {
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
6. Extract the Comparator for sorting
We can avoid defining comparison logic by using a reference to the instance method and the Comparator.comparing method, which extracts and creates a Comparable based on that function.
We’re going to use the getName() getter method to build the Lambda expression and sort the list by name:
@Test
public void givenInstanceMethod_whenSortingEntitiesByNameThenAge_thenCorrectlySorted() {
List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
Collections.sort(humans, Comparator.comparing(Human::getName));
Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
Copy the code
7. Reverse sort
JDK 8 also provides a useful way to reverse the Comparator (reverse Comparator) — we can quickly reverse our sorting:
@Test
public void whenSortingEntitiesByNameReversed_thenCorrectlySorted() {
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
8. Multi-conditional sorting
Lambda expressions for comparison operations are not always this simple — we could also write more complex expressions, such as sorting entities by name and then by age:
@Test
public void whenSortingEntitiesByNameThenAge_thenCorrectlySorted() {
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
9. Multi-condition combination sorting
The same comparison logic — sorting first by name and then by age — can be implemented using Comparator’s new combinatorial support.
Starting with JDK 8, we can now chain multiple comparators together to build more complex comparison logic:
@Test
public void givenComposition_whenSortingEntitiesByNameThenAge_thenCorrectlySorted() {
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
10 and summarize
This article illustrates a variety of exciting ways to sort lists using Java 8 Lambda expressions — the correct use of past syntactic sugar and real, useful semantics.
The implementations and code snippets for all of these examples are available on my Github project — it’s an Eclipse-based project, so it should be easy to import and run.
Welcome to Zhihu columnKeeping up with Java8, share excellent Java8 Chinese guides and tutorials, and welcome to contribute high-quality articles.
Original link:
baeldung
Translation:
ImportNew.com –
Into the forest
Translation link:
www.importnew.com/15259.html