Java中List排序的3种方法
在某些特殊的场景下,我们需要在 Java 程序中对 List 集合进行排序操作。比如从第三方接口中获取所有用户的列表,但列表默认是以用户编号从小到大进行排序的,而我们的系统需要按照用户的年龄从大到小进行排序,这个时候,我们就需要对 List 集合进行自定义排序操作了。
List 排序的常见方法有以下 3 种:
-
使用 Comparable 进行排序;
-
使用 Comparator 进行排序;
-
如果是 JDK 8 以上的环境,也可以使用 Stream 流进行排序。
下面我们分别来看各种排序方法的具体实现。
1.使用 Comparable 排序
按照本文设计的场景,我们需要创建一个包含了用户列表的 List 集合,并按用户的年龄从大到小进行排序,具体实现代码如下:
public class ListSortExample {public static void main(String[] args) {// 创建并初始化 ListList<Person> list = new ArrayList<Person>() {{add(new Person(1, 30, "北京"));add(new Person(2, 20, "西安"));add(new Person(3, 40, "上海"));}};// 使用 Comparable 自定的规则进行排序Collections.sort(list);// 打印 list 集合list.forEach(p -> {System.out.println(p);});}
}// 以下 set/get/toString 使用的是 lombok 的注解
@Getter
@Setter
@ToString
class Person implements Comparable<Person> {private int id;private int age;private String name;public Person(int id, int age, String name) {this.id = id;this.age = age;this.name = name;}@Overridepublic int compareTo(Person p) {return p.getAge() - this.getAge();}
}
以上代码的执行结果,如下图所示:
本方法的核心代码如下:
2.使用 Comparator 排序
Comparable 是类内部的比较方法,而 Comparator 是排序类外部的比较器。使用 Comparator 比较器,无需修改原 Person 类,只需要扩充一个 Person 类的比较器就行了,Comparator 的实现方法有以下两种:
-
新建 Comparator 比较器;
-
使用 Comparator 匿名类比较器。
其中,第二种实现方法要更简洁一些,我们通过下面的具体代码,来观察一下二者的区别。
2.1 新建 Comparator 比较器
public class ListSortExample2 {public static void main(String[] args) {// 创建并初始化 ListList<Person> list = new ArrayList<Person>() {{add(new Person(1, 30, "北京"));add(new Person(2, 20, "西安"));add(new Person(3, 40, "上海"));}};// 使用 Comparator 比较器排序Collections.sort(list, new PersonComparator());// 打印 list 集合list.forEach(p -> {System.out.println(p);});}
}
/*** 新建 Person 比较器*/
class PersonComparator implements Comparator<Person> {@Overridepublic int compare(Person p1, Person p2) {return p2.getAge() - p1.getAge();}
}
@Getter
@Setter
@ToString
class Person {private int id;private int age;private String name;public Person(int id, int age, String name) {this.id = id;this.age = age;this.name = name;}
}
以上代码的执行结果,如下图所示:
本方法的核心实现代码如下:
2.2 匿名类比较器
比较器 Comparator 可以使用更简洁的匿名类的方式,来实现排序功能,具体实现代码如下:
public class ListSortExample2 {public static void main(String[] args) {// 创建并初始化 ListList<Person> list = new ArrayList<Person>() {{add(new Person(1, 30, "北京"));add(new Person(2, 20, "西安"));add(new Person(3, 40, "上海"));}};// 使用匿名比较器排序Collections.sort(list, new Comparator<Person>() {@Overridepublic int compare(Person p1, Person p2) {return p2.getAge() - p1.getAge();}});// 打印 list 集合list.forEach(p -> {System.out.println(p);});}
}
@Getter
@Setter
@ToString
class Person {private int id;private int age;private String name;public Person(int id, int age, String name) {this.id = id;this.age = age;this.name = name;}
}
以上代码的执行结果,如下图所示:
3.使用 Stream 流排序
在 JDK 8 之后可以使用更加简单的方法 Stream 流来实现排序功能,它的实现只需要一行代码,具体实现如下:
public class ListSortExample3 {public static void main(String[] args) {// 创建并初始化 ListList<Person> list = new ArrayList<Person>() {{add(new Person(1, 30, "北京"));add(new Person(2, 20, "西安"));add(new Person(3, 40, "上海"));}};// 使用 Stream 排序list = list.stream().sorted(Comparator.comparing(Person::getAge).reversed()).collect(Collectors.toList());// 打印 list 集合list.forEach(p -> {System.out.println(p);});}@Getter@Setter@ToStringstatic class Person {private int id;private int age;private String name;public Person(int id, int age, String name) {this.id = id;this.age = age;this.name = name;}}
}
其中 reversed() 表示倒序的意思,如果不使用此方法则是正序。
以上代码的执行结果,如下图所示:
扩展:排序字段为 null
使用 Stream 进行排序时,如果排序的字段出现 null 值就会导致异常发生,具体示例如下:
public class ListSortExample4 {public static void main(String[] args) {// 创建并初始化 ListList<Person> list = new ArrayList<Person>() {{add(new Person(30, "北京"));add(new Person(10, "西安"));add(new Person(40, "上海"));add(new Person(null, "上海")); // 年龄为 null 值}};// 按照[年龄]正序,但年龄中有一个 null 值list = list.stream().sorted(Comparator.comparing(Person::getAge)).collect(Collectors.toList());// 打印 list 集合list.forEach(p -> {System.out.println(p);});}
}
@Getter
@Setter
@ToString
class Person {private Integer age;private String name;public Person(Integer age, String name) {this.age = age;this.name = name;}
}
以上代码的执行结果,如下图所示:
想要解决上述问题,需要给 Comparator.comparing 传递第二个参数:Comparator.nullsXXX,如下代码所示:
public class ListSortExample4 {public static void main(String[] args) {// 创建并初始化 ListList<Person> list = new ArrayList<Person>() {{add(new Person(30, "北京"));add(new Person(10, "西安"));add(new Person(40, "上海"));add(new Person(null, "上海"));}};// 按照[年龄]正序,但年龄中有一个 null 值list = list.stream().sorted(Comparator.comparing(Person::getAge,Comparator.nullsFirst(Integer::compareTo))).collect(Collectors.toList());// 打印 list 集合list.forEach(p -> {System.out.println(p);});}
}
@Getter
@Setter
@ToString
class Person {private Integer age;private String name;public Person(Integer age, String name) {this.age = age;this.name = name;}
}
Comparator.nullsFirst 表示将排序字段中的 null 值放到集合最前面,如果想要将 null 值放到集合最后面可以使用 Comparator.nullsLast。
以上代码的执行结果,如下图所示:
总结
本文介绍了 3 种 List 排序的方法,前两种方法常用于 JDK 8 之前的版本,其中比较器 Comparator 有两种实现的写法,而在 JDK 8 之后的版本,就可以使用 Comparator.comparing 实现排序了,如果排序字段中可能出现 null 值,要使用 Comparator.nullsXXX 进行排序处理(否则会报错)
相关文章:
Java中List排序的3种方法
在某些特殊的场景下,我们需要在 Java 程序中对 List 集合进行排序操作。比如从第三方接口中获取所有用户的列表,但列表默认是以用户编号从小到大进行排序的,而我们的系统需要按照用户的年龄从大到小进行排序,这个时候,…...
flutter-读写二进制文件到设备
看了下很多文章,本地文件存储都只有存储txt文件,我们探索下存储二进制文件吧。 保存二进制文件到设备硬盘上。 我们保存一个图片到手机本地上,并读取展示图片到app上。 以百度logo图为例子 写入图片 逻辑如下: 获取本地路径 -&g…...
C语言基础知识:内存分配
目录 内存分配原理 内存分配方法 静态内存分配 动态内存分配 MALLOC() CALLOC() 内存释放 注意事项 在C语言中,内存分配是非常重要的一个概念,因为C语言中没有内置的垃圾回收机制,需要我们手动管理内存的分配和释放。下面我们来详细讲…...
【Simulink】示波器图形数据导入Matlab重新绘图(论文)
版本:Matlab2019b 效果 示波器波形图片: 黑色背景,而且坐标轴字体较小,不方便修改,不能直接用在论文上面 对比 Matlab 绘图: 接下来介绍如何设置~ Simulink 设置 选择需要导入的示波器数据 点击 Vi…...
汇编调试及学习
汇编调试 打印寄存器的值 打印内存地址 打印8字节,就是64位 打印格式 是从低位取过来的 b 字节 h 双字节 w四字节 g八字节 前变基 后变基 。 后变基这个变基会发生变化的。前变基变基不会发生变化需要用!号。 前变基 , 加了࿰…...
Linux - 第19节 - 网络基础(传输层二)
1.TCP相关实验 1.1.理解listen的第二个参数 在编写TCP套接字的服务器代码时,在进行了套接字的创建和绑定之后,需要调用listen函数将创建的套接字设置为监听状态,此后服务器就可以调用accept函数获取建立好的连接了。其中listen函数的第一个参…...
web实现日历、阳历农历之间相互转换、npm、push、unshift、includes、innerHTML
文章目录 1、原生web实现效果图htmlJavaScriptstyle vue2实现htmlJavaScript 1、原生web实现 效果图 html <div class"box"><div class"week"><div>星期日</div><div>星期一</div><div>星期二</div><…...
GcExcel v6.1 支持新的 ‘.sjs‘ 模板文件 ‘.xltx‘ 格式 Crack
GrapeCity Documents for Excel (GcExcel) v6.1 版本现已上线!该版本支持新的 SpreadJS .sjs 文件格式和 Excel 模板文件 .xltx 格式。此外,GcExcel 支持更多的SpreadJS兼容性功能和对 GcDataViewer 的多项增强。看看下面的主要亮点。 导入/导出 Spread…...
面试官:MySQL自增主键一定是连续的吗?
测试环境: MySQL版本:8.0 数据库表:T (主键id,唯一索引c,普通字段d) 如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的…...
2023ACP世界大赛教育者论坛:让职业教育直面AI机遇与挑战
“AI技术的普及对创意行业和教育带来的影响和变革-2023 Adobe Certified Professional教育者论坛”在苏州西交利物浦大学成功举办。 本次论坛,由Adobe Certified Professional 世界大赛中国赛区组委会主办,联动了来自院校、海内外杰出的创意公司及国际知…...
Unity基础 音频组件以及音频播放
在游戏开发中,声音是一个重要的环节。Unity中的声音组件可以帮助开发者轻松地控制游戏中音频的播放、音量、循环等属性,从而实现更好的游戏体验。本文将详细介绍Unity声音组件的相关概念和技术,以及其在游戏、影视等领域的广泛应用和发展前景…...
SAP-MM-采购申请审批那些事!
1、ME55不能审批删除行项目的PR 采购申请审批可以设置行项目审批或抬头审批。如果设置为抬头审批时,ME55集中审批时,就会发现有些采购申请时不能审批的, 那么这些采购申请时真的不需要审批么?不是的,经过核对这些采购申…...
专业解读财务共享实现财务数智化转型的有效路径
近年来,随着数字经济的飞速发展,各大企业全面开启数智化转型之路,作为企业数智化转型的重要内容,财务数智化转型始于财务共享服务。然而,财务共享建设并不是一蹴而就的,如何通过财务共享实现财务数智化转型…...
九章云极DataCanvas公司诚邀您共享AI基础软件前沿技术盛宴
“杭州通用人工智能论坛暨AIIA人工智能产业发展大会”将于2023年5月30日-31日在杭州举办。本次人工智能产业发展大会由中国信息通信研究院、中国人工智能产业发展联盟主办,杭州城西科创大走廊管委会、杭州市经济和信息化局、杭州未来科技城管理委员会、人工智能关键…...
【高级语言程序设计(一)】第 10 章:文件
目录 一、文件概述 (1)文件定义 (2)文件命名 (3)文件分类 ① 按照文件的内容划分 ② 按照文件的组织形式划分 ③ 按照文件的存储形式划分 ④ 按照文件的存储介质划分 (4)文…...
Android 宿主启动插件中的Activity和Service
在宿主App中加载插件App中的四大组件,需要以下几个步骤: 1. 预先在宿主的AndroidManifest文件中声明插件中的四大组件 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.co…...
00后卷王自述,我真的很卷吗?
前段时间我去面试了一个软件测试公司,成功拿到了offer,薪资也从10k涨到了18k,对于工作都还没两年的我来说,还是比较满意的,毕竟有些工作了3到4年的可能还没有我的高。 在公司一段时间后大家都说我是卷王,其…...
真题详解(树的结点)-软件设计(八十四)
真题详解(汇总)-软件设计(八十三)https://blog.csdn.net/ke1ying/article/details/130856130?spm1001.2014.3001.5501 COCOMOII估算不包括_____。 对象点 B.功能点 C.用例数 D.源代码行 答案:C 语法翻译是一种ÿ…...
LDA算法实现鸢尾花数据集降维
目录 1. 作者介绍2. LDA降维算法2.1 基本概念2.2 算法流程 3. LDA算法实现3.1 数据集介绍3.2 代码实现3.3 结果展示 1. 作者介绍 唐杰,男,西安工程大学电子信息学院,2022级研究生 研究方向:机器视觉与人工智能 电子邮件ÿ…...
深入理解Linux虚拟内存管理
系列文章目录 Linux 内核设计与实现 深入理解 Linux 内核(一) 深入理解 Linux 内核(二) Linux 设备驱动程序(一) Linux 设备驱动程序(二) Linux 设备驱动程序(三…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
