Java 中 List 排序的 3 种方法

news2024/11/19 1:29:08

在某些特殊的场景下,我们需要在 Java 程序中对 List 集合进行排序操作。比如从第三方接口中获取所有用户的列表,但列表默认是以用户编号从小到大进行排序的,而我们的系统需要按照用户的年龄从大到小进行排序,这个时候,我们就需要对 List 集合进行自定义排序操作了。

List 排序的常见方法有以下 3 种:

  • 使用 Comparable 进行排序;

  • 使用 Comparator 进行排序;

  • 如果是 JDK 8 以上的环境,也可以使用 Stream 流进行排序。

下面我们分别来看各种排序方法的具体实现。

1.使用 Comparable 排序

按照本文设计的场景,我们需要创建一个包含了用户列表的 List 集合,并按用户的年龄从大到小进行排序,具体实现代码如下:

public class ListSortExample {
    public static void main(String[] args) {
        // 创建并初始化 List
        List<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) {
        // 创建并初始化 List
        List<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) {
        // 创建并初始化 List
        List<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) {
        // 创建并初始化 List
        List<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) {
        // 创建并初始化 List
        List<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) {
        // 创建并初始化 List
        List<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 进行排序处理(否则会报错)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/159826.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.1.1信号的概念、描述及分类

目录 1.信号的概念 2.描述 3.分类 3.1确定信号和随机信号 ​3.2连续信号和离散信号​​​​​​​ 两者之间存在这样一种关系 3.3周期信号和非周期信号 3.4能量信号和功率信号 一些例题 1.信号的概念 信号是表示消息的 物理量 &#xff0c;如电信号可以通过 幅度 、 …

23.指针数组的概念,定义方法

1.二维数组 二维数组有行有列&#xff0c;二维数组可以看成由多个一维数组构成的&#xff0c;是多个一维数组的集合&#xff0c;可以认为二维数组的每一个元素都是一个一维数组。 #include<stdio.h> int main() {int a[3][5];printf("a%p\n",a);printf("…

Zabbix与乐维监控对比分析(八)——其他功能篇

前面我们详细介绍了Zabbix与乐维监控的架构与性能、Agent管理、自动发现、权限管理、对象管理、告警管理、可视化、图形图表及网络功能方面的对比分析&#xff0c;接下来我们将对二者其他功能进行对比分析。 本篇是Zabbix与乐维监控对比分析专题系列文章的第八篇&#xff0c;也…

Visual Studio Code快捷键的使用-RK3568开发

在 Visual Studio Code 软件中使用快捷键可以增加自身的效率&#xff0c;一些常用的快捷键如下所 示&#xff1a; F1 打开可以输入命令 F2 重命名变量&#xff0c;方便重构 F5 运行和调试代码 F12 去到定义的地方 shiftF12 查找所有引用 ctrlg 会让你输入数字&#xff0c;快速定…

SpringBoot2源码1-嵌入式Tomcat启动和@SpringBootApplication注解原理

1. 测试案例 1.1 引入依赖 <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.5</ve…

看完RabbitMQ了的几种消息模型,我对RabbitMQ有了新的认识

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;曾经在某央企公司实习&#xff0c;目前在某税务公司。前面已经记录了两种消息模型知识&#xff0c;因此本篇文章将记录和分享剩下的RabbitMQ几种消息模型相关知识点。 本篇文章记录的基础知识&am…

锁策略和synchronized

1.常见的锁策略&#xff08;1&#xff09;乐观锁 和 悲观锁乐观锁&#xff1a;预测锁竞争的情况不激烈&#xff08;工作量较少&#xff09;悲观锁&#xff1a;预测锁竞争的情况很激烈&#xff08;工作量较多&#xff09;&#xff08;2&#xff09;轻量级锁 和 重量级锁轻量级锁…

IDEA Alibaba代码格式化(EclipseCodeFormatter)

1.阿里模板下载地址https://github.com/alibaba/p3c/tree/master/p3c-formatter2.下载阿里配置文件&#xff08;eclipse-codestyle.xml&#xff09;&#xff0c;因为此文件是针对ecplice的&#xff0c;在IDEA中使用配置文件&#xff0c;需要安装Eclipse Code Formatter插件3.配…

文档控件 Aspose.PDF for Java 授权须知

Aspose.PDF是一款高级PDF处理API&#xff0c;可以在跨平台应用程序中轻松生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现&#xff0c;保护和打印文档。无需使用Adobe Acrobat。此外&#xff0c;API提供压缩选项&#xff0c;表创建和处理&#xff0c;图形和图像功能&…

马蹄集 卡罗尔数

卡罗尔数 难度&#xff1a;白银 0时间限制&#xff1a;1秒 巴占用内存&#xff1a;64M 卡罗尔数是其值满足4n-2(n1)-1的整数(n为正整数)。输入正整 数N判断它是不是卡罗尔数&#xff0c;输出YES或者NO。 #include <bits/stdc.h>> using namespace std; int main(…

SpringMVC超详解

SpringMVC超详解1、SpringMVC简介1.1、什么是MVCMVC是一种软件架构的思想&#xff0c;将软件按照模型、视图、控制器来划分M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据JavaBean分为两类&#xff1a;一类称为实体类Bean&…

算法拾遗二十四之暴力递归到动态规划二

算法拾遗二十四之暴力递归到动态规划二背包问题一优化题目二优化题目三&#xff08;贴纸拼词&#xff09;优化题目四&#xff1a;最长公共子序列优化背包问题一 weights[i]和values[i]的值都是大于等于0的&#xff0c;不存在负数的情况。 可以从尝试入手&#xff0c;改动态规划…

基于智能矿山电力监控系统的设计与应用方法

摘要&#xff1a;随着煤矿建设的智能化程度越来越高&#xff0c;构建智能电力监控系统实现对矿山生产的有效监控至关重要。首先分析了矿山电力监控系统存在的主要问题&#xff0c;其次重点介绍了基于智能矿山电力监控系统的设计过程&#xff0c;后提出了加强智能电力监控系统的…

Inspur KOS 龙蜥衍生版面向智慧新媒体转型的探索与实践 | 龙蜥案例

编者按&#xff1a;日前&#xff0c;龙蜥社区理事单位浪潮信息正式对外发布基于龙蜥操作系统&#xff08;Anolis OS&#xff09;的服务器操作系统 Inspur KOS&#xff0c;并基于 Inspur KOS 推出可视化迁移方案 C2K&#xff0c;该方案能够将用户应用安全可靠地切换到 Inspur KO…

【系列02】Java流程控制 scanner 选择结构 循环结构语句使用 [有目录]

Scanner输入 Next和NextLine区别 NextLine 用的会多点 因为Next遇到空格就断开了 next语法使用 package com.SunAo.scanner; import java.util.Scanner; public class Demo01 {public static void main(String[] args) {//创建扫描器用来接收 键盘输入Scanner scanner new …

李宏毅ML-批次与动量

批次与动量 文章目录批次与动量1. Small batch or Large batch?2. Gradient descent Momentum3. 总结1. Small batch or Large batch? 在使用 gradient descent 进行 optimization 时&#xff0c;在每一次 epoch 前&#xff0c;要 shuffle 所有的资料&#xff0c;然后再分成…

无桌面Centos7系统安装Cypress@9.0.0并运行

一、安装Cypress 安装前准备 1、安装npm 下载安装包 cd /usr/local mkdir node cd node wget https://npm.taobao.org/mirrors/node/v15.8.0/node-v15.8.0-linux-x64.tar.gz ls -l解压这个包 tar -zxvf node-v15.8.0-linux-x64.tar.gz 你会发现已经有一个node的目录解压…

11、Javaweb_JSPMVCELJSTL三层架构用户列表案例

JSP: 1. 指令 * 作用&#xff1a;用于配置JSP页面&#xff0c;导入资源文件 * 格式&#xff1a; <% 指令名称 属性名1属性值1 属性名2属性值2 ... %> * 分类&#xff1a; 1. page &#xff1a; 配置JSP页面的 * content…

①【Spring】一文了解IOC容器

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 一文掌握IOC一、IOC二、IOC容器的实现BeanFact…

一文掌握fastapi微服务开发

目录 一、概述 1.1 微服务 1.1.1 微服务的优势 1.1.2 微服务的缺点 1.2 为何使用Python开发微服务 1.3 FastAPI概述 二、开发 2.1 安装FastAPI 2.1.1 安装虚拟环境 2.1.2 创建虚拟环境 2.1.3 激活虚拟环境 2.1.4 安装FastAPI 2.2 FastAPI简单使用 2.2.1 查询 2.…