Java8函数之旅 (五) -- Java8中的排序
前言
对数据进行排序是平常经常会用到的操作之一,使用Jav8排序可以减少你在排序这方面的代码量,优化你的代码。
测试用例代码
定义个实体类User,拥有姓名name,年龄age,积分credits三个属性,定义一个包含User的集合,用于排序,下面是代码
/* 这里偷个懒,用lombok注解生成实体类getset等一些基本方法 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private Integer age;
private Integer credits;
}
初始化待排序的集合
private List<User> users = Lists.newArrayList(
new User("jack",17,10),
new User("jack",18,10),
new User("jack",19,11),
new User("apple",25,15),
new User("tommy",23,8),
new User("jessica",15,13)
);
排序
对年龄从小到大排序
Before Java8
根据User年龄从小到大排序,使用Collections.sort方法,通过Comparator的匿名内部类实现
@Test
public void traditionCompareByName(){
Collections.sort(users, new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.getAge() - o2.getAge();
}
});
for (User user : users) {
System.out.println(user);
}
}
结果
User(name=jessica, age=15, credits=13)
User(name=jack, age=17, credits=10)
User(name=jack, age=18, credits=10)
User(name=jack, age=19, credits=11)
User(name=tommy, age=23, credits=8)
User(name=apple, age=25, credits=15)
Process finished with exit code 0
in Java8
这里使用lambda表达式来代替匿名内部类,并且使用list接口下的sort方法(java8新增加),再链式输出
@Test
public void traditionCompareByNameInJava8(){
users.sort((o1, o2) -> o1.getAge() - o2.getAge());
users.forEach(user -> System.out.println(user));
}
输出结果就不再显示了
当然还可以通过方法引用进一步的简化,这里使用Comparator下的comparingInt进行排序,使用User::getAge获得年龄,默认从小到大正向排序
import static java.util.Comparator.comparingInt;
@Test
public void traditionCompareByNameInJava8(){
users.sort(comparingInt(User::getAge));
users.forEach(System.out::println);
}
对比
简单对比一下,可以发现使用Java8的排序对于简单的排序无论是从代码量还是可以阅都是比之前的匿名内部类实现compare方法要好的。
对年龄从大到小排序(反向排序)
Before Java8
同样是通过匿名内部类这是这次将 o1 - o2 的顺序调换一下
@Test
public void traditionCompareByNameReverse(){
Collections.sort(users, new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o2.getAge() - o1.getAge();
}
});
}
In Java8
和匿名内部类的颠倒一样,只是这里有之间的类库反转
@Test
public void traditionCompareByNameInJava8Reverse(){
users.sort((o1, o2) -> o1.getAge() - o2.getAge());
}
在比较器后面增加reversed即可,链式调用是java8的风格之一
@Test
public void traditionCompareByNameInJava8Reverse(){
users.sort(comparingInt(User::getAge).reversed());
}
同样是阅读性,原先的匿名内部类方法不仅阅读困难,一个简单的倒序也需要先去观察o2-o1还是o1-o2才能得出,而Java8的方法不仅代码简洁,可读性还很高,compare getAge读出是通过年龄进行排序,reversed读出是倒序。
根据姓名,年龄,积分排序
按照姓名,年龄与积分的顺序依次排序,也就是多条件组合排序
Before Java8
让我们看看传统的方式该如何实现
@Test
public void traditionCombinationCompare(){
Collections.sort(users, new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
if (o1.getName().equals(o2.getName())) {
if (o1.getAge().equals(o2.getAge())) {
return o1.getAge() - o2.getAge();
} else {
return o1.getCredits() - o2.getCredits();
}
} else {
return o1.getName().compareTo(o2.getName());
}
}
});
}
这样的代码我相信谁都不太想看,我自己写完都需要验证一遍以保证真的没有哪里逻辑写错,这样的做法不仅效率底下,还容易犯错,这种代码更是他人的噩梦。
in Java8
- 在这里我们使用比较器的
thenComparing实现链式调用
@Test
public void traditionCombinationCompareInJava8(){
users.sort(comparing(User::getName)
.thenComparing(User::getAge)
.thenComparing(User::getCredits));
}
可读性也很好,这样的代码几乎连注释都省去了,很清晰的可以看出排序的顺序,修改起来也很容易,而上面的代码如果要修改成另外一种次序,整个嵌套逻辑结构条件都要改动。
- 另外如果需求变成如下,按照姓名顺序->年龄倒序->积分顺序的次序来排序,Java8也十分容易,comparing比较器提供了重载方法,可以自定义某条属性的排序,例子如下
@Test
public void traditionCombinationCompareInJava8(){
users.sort(comparing(User::getName)
.thenComparing(User::getAge, (o1, o2) -> o2 - o1)
.thenComparing(User::getCredits));
}
- update(10-24)
事实上o2 - o1这样的代码还是有一些命令式的风格,即包含了具体的实现过程(o2 -o1这样的代码),thenComparaing方法可以直接接受一个排序器,因此我们只要直接将倒序的排序器当做参数传入即可,代码如下
@Test
public void traditionCombinationCompareInJava8(){
users.sort(comparing(User::getName)
.thenComparing(comparing(User::getAge).reversed())
.thenComparing(User::getCredits));
users.forEach(System.out::println);
}
很清晰的可以看到第二行的getAge是倒序,而其他的属性依旧是正序,建议大家使用链式写法的时候像上面一样分行,提高可读性
总结
- 使用lambda表达式可以代替传统的匿名内部类,精简代码量,提高可读性,可以进一步使用方法引用继续精简
- 使用Comparing的比较器加上链式调用可以很方便的完成逆序,多属性组合排序等排序情况,代码精简,阅读性高
- 使用链式调用建议按照.功能分行写,便于阅读
希望这篇文章能对你有所帮助
Java8函数之旅 (五) -- Java8中的排序的更多相关文章
- Java8函数之旅 (二) --Java8中的流
流与集合 众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...
- Java8函数之旅 (七) - 函数式备忘录模式优化递归
前言 在上一篇开始Java8之旅(六) -- 使用lambda实现Java的尾递归中,我们利用了函数的懒加载机制实现了栈帧的复用,成功的实现了Java版本的尾递归,然而尾递归的使用有一个重要的条件就是 ...
- Java8函数之旅 (八) - 组合式异步编程
前言 随着多核处理器的出现,如何轻松高效的进行异步编程变得愈发重要,我们看看在java8之前,使用java语言完成异步编程有哪些方案. JAVA8之前的异步编程 继承Thead类,重写run方法 实现 ...
- Java8函数之旅(四) --四大函数接口
前言 Java8中函数接口有很多,大概有几十个吧,具体究竟是多少我也数不清,所以一开始看的时候感觉一脸懵逼,不过其实根本没那么复杂,毕竟不应该也没必要把一个东西设计的很复杂. 几个单词 在学习 ...
- Java8函数之旅 (一) 开始认识lambda
系列之前我想说的 最近有一段时间没写博客了,这几天回到学校,才闲下来,决定写一写最近学习到的知识,既是为了分享,也是为了巩固.之前看到过一篇调查,调查说的是学习新知识,光只是看的话,知识的获取率只 ...
- Java8函数之旅 (三) --几道关于流的练习题
为什么要有练习题? 所谓学而不思则罔,思而不学则殆,在系列第一篇就表明我认为写博客,既是分享,也是自己的巩固,我深信"纸上得来终觉浅,绝知此事要躬行"的道理,因此之后的几篇博 ...
- Java8函数之旅 (六) -- 使用lambda实现Java的尾递归
前言 本篇介绍的不是什么新知识,而是对前面讲解的一些知识的综合运用.众所周知,递归是解决复杂问题的一个很有效的方式,也是函数式语言的核心,在一些函数式语言中,是没有迭代与while这种概念的,因为此类 ...
- Java8学习笔记(五)--Stream API详解[转]
为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念.它也不同于 StAX 对 ...
- 为什么局部变量必须以final修饰(或者有final实效:java8)才可以在内部类中使用?
为什么局部变量必须以final修饰(或者有final实效:java8)才可以在内部类中使用? public class Ace { public static void main(String[] a ...
随机推荐
- C#学习笔记---数据库连接与异常
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...
- hive中一些常用的sql语句
1.建表 CREATE TABLE IF NOT EXISTS student( time varchar(64) , num int , age int )PARTITIONED BY ( scor ...
- NB-IoT物联网,来了
日前,深圳移动联合华为公司在深圳市福田.前海及盐田区域部署NB-IoT/LTE融合站点130余个,完成NB-IoT系统关键技术验证和组网技术验证,已初步形成NB-IoT试商用条件.深圳移动后续将在深圳 ...
- nefu 115 循环节
斐波那契的整除 Problem:115 Time Limit:1000ms Memory Limit:65536K Description 已知斐波那契数列有如下递归定义,f(1)=1,f(2)=1, ...
- thinkphp整合系列之极验滑动验证码
对于建站的筒子们来说:垃圾广告真是让人深恶痛绝:为了清净:搞个难以识别的验证码吧:又被用户各种吐槽:直到后来出现了极验这个滑动的验证码:这真是一个体验好安全高的方案:官网:http://www.gee ...
- FastDFS教程Ⅲ-文件服务器扩容
1.简介 FastDFS文件服务器在设计时,为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式.存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是 ...
- 利用模板template动态渲染jsp页面
一.场景 在js中写html简直是噩梦,刚进新公司,在codereview的时候得知可以通过将html模板写在jsp页面,然后由js调取模板,利用replace()方法替换传值的方式避免在js中拼接h ...
- 通过Javascript调用微软认知服务情感检测接口的两种实现方式
这是今天在黑客松现场写的代码.我们的项目需要调用认知服务的情感识别接口.官方提供了一种方式,就是从一个远程图片进行识别.我另外写了一个从本地文件读取并上传进行识别的例子. 官方文档,请参考 https ...
- CS Round#49 C Max Substring
Max Substring Time limit: 1000 msMemory limit: 256 MB You are given a string S. Find a string T th ...
- html和css的区别
html(结构) Hyper Text Markup Language(超文本标记语言)用于定义文档内容结构 1.该语言写的代码通常会被浏览器解析执行 2.超文本:不止包括文本,还有图片.链接.音乐. ...