- Java 8:Lambda 序列化?
- Java 8 lambda 最佳实践
- Java 8 lambda 表达式 10 个示例
- Java8 lambda 表达式 10 个示例
- Java8 Lambda 表达式和流操作如何让你的代码变慢 5 倍
- Java8:Lambda 表达式增强版 Comparator 和排序
- Java 8 LongAdders:管理并发计数器的正确方式
- Java 8 Optional 类深度解析
- Java8 中的 java.util.Random 类
- Java8 中的简易并发
- Java8 学习:Lambda 表达式、Stream API 和功能性接口 — 教程、资源、书籍和实例
- Java8 并发教程:Threads 和 Executors
- Java 8 新特性之旅:使用 Stream API 处理集合
- Java 8 新特性探究(一)通往 lambda 之路_语法篇
- Java 8 新特性探究(六)泛型的目标类型推断
- Java 8 新特性探究(七)深入解析日期和时间-JSR310
- Java 8 新特性探究(八)精简的 JRE 详解
- Java 8 新特性探究(九)跟 OOM:Permgen 说再见吧
- 总结
- Java 8 新特性探究(十)StampedLock 将是解决同步问题的新宠
- Java 8 新特性探究(十一)Base64 详解
- Java 8 新特性探究(十二)Nashorn :新犀牛
- Java 8 新特性终极指南
- Java 8 新的时间日期库的 20 个使用示例
- Java8 日期时间(Date Time)API 指南
- Java8 本地缓存
- Java 8 的 default 方法能做什么?不能做什么?
- Java 8 的 6 个问题
- Java 8 简明教程
- Java8 集合中的 Lambda 表达式
- Java SE 8 新的时间和日期 API
- 在 Java 8 下更好地利用枚举
- 在 Java 8 中避免 Null 检查
- 鲜为人知的 Java8 特性:泛化目标类型推断
Java8:Lambda 表达式增强版 Comparator 和排序
1、概述
在这篇教程里,我们将要去了解下即将到来的 JDK 8 (译注,现在 JDK 8 已经发布了) 中的 Lambda 表达式——特别是怎样使用它来编写 Comparator 和对集合(Collection)进行排序。
这篇文章是 Baeldung 上的 “Java ——回归基础”(“Java – Back to Basic”)系列 的一部分。
首先,让我们先定义一个简单的实体类:
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
}
2、不使用 Lambda 表达式的基本排序
在 Java 8 之前,对集合进行排序要 为 Comparator 创建一个匿名内部类 用来排序:
new Comparator<Human>() {
@Override
public int compare(Human h1, Human h2) {
return h1.getName().compareTo(h2.getName());
}
}
简单地用它来对 Human 实体列表进行排序:
@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) {
return h1.getName().compareTo(h2.getName());
}
});
Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
3、使用 Lambda 表达式的基本排序
根据 Lambda 表达式的介绍,我们现在可以不使用匿名内部类,只使用 简单实用的语义 就可以得到相同的结果。
(final Human h1, final Human h2) -> h1.getName().compareTo(h2.getName());
类似地,我们现在可以像之前那样来测试它的行为:
@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)));
}
注意:我们同样使用 新的 sort API,这个 API 在 Java 8 里被添加到 java.util.List ——而不是旧的 Collections.sort API。
4、没有类型定义( Type Definitions)的基本排序
我们通过不指定类型定义来进一步简化表达式 —— 编译器自己可以进行类型判断 :
(h1, h2) -> h1.getName().compareTo(h2.getName())
测试仍然很相似:
@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)));
}
5、使用静态方法的引用来排序
下面我们将要使用带有静态方法引用的 Lambda 表达式去进行排序。
首先,我们要定义 compareByNameThenAge 方法 ——这个方法拥有与 Comparator 对象里的 compareTo 方法完全相同的签名:
public static int compareByNameThenAge(Human lhs, Human rhs) {
if (lhs.name.equals(rhs.name)) {
return lhs.age - rhs.age;
} else {
return lhs.name.compareTo(rhs.name);
}
}
现在,我们要使用这个引用去调用 humans.sort 方法:
humans.sort(Human::compareByNameThenAge);
最终结果是一个使用静态方法作为 Comparator 的有效的排序集合:
@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)));
}
6、提取 Comparator 进行排序
我们可以通过使用 实例方法的引用 和 Comparator.comparing 方法来避免定义比较逻辑——它会提取和创建一个基于那个函数的 Comparable。
我们准备使用 getName() getter 方法去建造 Lambda 表达式并通过 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)));
}
7、反转排序
JDK 8 同样提供了一个有用的方法用来 反转 Comparator(reverse Comparator) ——我们可以快速地利用它来反转我们的排序:
@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)));
}
8、多条件排序
比较操作的 Lambda 表达式不一定都是这么简单的——我们 同样可以编写更复杂的表达式, 比如先根据 name 后根据 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 {
return lhs.getName().compareTo(rhs.getName());
}
});
Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));
}
9、多条件组合排序
同样的比较逻辑——先根据 name 进行排序其次是 age,同样可以通过 Comparator 新的组合支持来实现。
从 JDK 8 开始,我们现在可以把多个 Comparator 链在一起(chain together) 去建造更复杂的比较逻辑:
@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)));
}
10、总结
这篇文章举例说明了多种令人兴奋的方法: 使用 Java 8 Lambda 表达式对列表进行排序 ——正确使用过去的语法糖和真正、强大实用的语义。
所有这些例子的实现和代码片段都可以在 我的 github 项目 上获取到——这是一个基于 Eclipse 的项目,所以它应该很容易被导入和运行。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论