先定義一個實體類
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Human {
private String name;
private int age;
}
下面的操作都基於這個類來進行操作。這里面使用了Lombok類庫,它用注解的方式實現了基本的get和set等方法,讓代碼看起來更加的優雅。
JAVA8之前的List排序操作
在Java8之前,對集合排序只能創建一個匿名內部類
new Comparator<Human>() {
@Override
public int compare(Human h1, Human h2) {
return h1.getName().compareTo(h2.getName());
}
}
下面是簡單的對Humans進行排序(按名稱正序)
@Test
public void testSortByName_with_plain_java() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("li", 25)
);
Collections.sort(humans, new Comparator<Human>() {
public int compare(Human h1, Human h2) {
return h1.getName().compareTo(h2.getName());
}
});
Assert.assertThat(humans.get(0), equalTo(new Human("li", 25)));
}
使用Lambda的List排序
使用JAVA8函數式方式的比較器
(Human h1, Human h2) -> h1.getName().compareTo(h2.getName())
下面是使用JAVA8函數式的比較的例子
@Test
public void testSortByName_with_lambda() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("li", 25)
);
humans.sort((Human h1, Human h2) -> h1.getName().compareTo(h2.getName()));
Assert.assertThat("tomy", equalTo(humans.get(1).getName()));
}
沒有類型定義的排序
對於上面的表達式還可以進行簡化,JAVA編譯器可以根據上下文推測出排序的類型:
(h1, h2) -> h1.getName().compareTo(h2.getName())
簡化后的比較器是這樣的:
@Test
public void testSortByNameSimplify_with_lambda() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("li", 25)
);
humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName()));
Assert.assertThat("tomy", equalTo(humans.get(1).getName()));
}
使用靜態方法引用
JAVA8還可以提供使用Lambda表達式的靜態類型引用,我們在Human類增加一個靜態比較方法,如下:
public static int compareByNameThenAge(Human h1, Human h2) {
if (h1.getName().equals(h2.getName())) {
return Integer.compare(h1.getAge(), h2.getAge());
}
return h1.getName().compareTo(h2.getName());
}
然后就可以在humans.sort使用這個引用
@Test
public void testSort_with_givenMethodDefinition() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("li", 25)
);
humans.sort(Human::compareByNameThenAge);
Assert.assertThat("tomy", is(equalTo(humans.get(1).getName())));
}
使用單獨的Comparator
JAVA8已經提供了很多方便的比較器供我們使用,比如Comparator.comparing方法,所以可以使用Comparator.comparing方法來實現根據Human的name進行比較的操作:
@Test
public void testSort_with_givenInstanceMethod() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("li", 25)
);
Collections.sort(humans, Comparator.comparing(Human::getName));
Assert.assertThat("tomy", equalTo(humans.get(1).getName()));
}
反序
JDK8中也提供了一個支持倒序排序的方法方便我們更快的進行倒序
@Test
public void testSort_with_comparatorReverse() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("li", 25)
);
Comparator<Human> comparator = (h1, h2) -> h1.getName().compareTo(h2.getName());
humans.sort(comparator.reversed());
Assert.assertThat("tomy", equalTo(humans.get(0).getName()));
}
使用多個條件進行排序
Lambda提供了更復雜的表達式,還可以先對name排序再根據age進行排序:
@Test
public void testSort_with_multipleComparator() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("li", 25)
);
Comparator<Human> comparator = (h1, h2) -> {
if (h1.getName().equals(h2.getName())) {
return Integer.compare(h1.getAge(), h2.getAge());
}
return h1.getName().compareTo(h2.getName());
};
humans.sort(comparator.reversed());
Assert.assertThat("tomy", equalTo(humans.get(0).getName()));
}
使用多個條件進行排序-組合的方式
Comparator對這種組合的排序有更優雅實現,從JDK8開始,我們可以使用鏈式操作進行復合操作來構建更復雜的邏輯:
@Test
public void testSort_with_multipleComparator_composition() throws Exception {
ArrayList<Human> humans = Lists.newArrayList(
new Human("tomy", 22),
new Human("tomy", 25)
);
humans.sort(Comparator.comparing(Human::getName).thenComparing(Human::getAge));
Assert.assertThat(humans.get(0), equalTo(new Human("tomy", 22)));
}
總結
JDK8真的是一個非常值得我們學習的版本,它提供了Lambda表達式,帶來了函數式編程的理念,讓JAVA代碼更優雅。
所有的完整的代碼在這里