Java中List排序的3种方法
Posted 老程不秃
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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)
// 创建并初始化 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;
@Override
public 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>
@Override
public 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>()
@Override
public 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
@ToString
static 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 进行排序处理(否则会报错)。
通过Java排序List集合的元素的几种方法
用Java工具类Collections的sort()方法,对List集合元素进行排序。
Collections提供两种排序方法:
一、Collections.sort(List<T> list);
此方法需要泛型T这个Bean实现Comparable<T>接口,并且实现compareTo()方法排序;
二、Collections.sort(List<T> list, Comparator<? super T> c);
此方法,在泛型T这个Bean没有实现Comparable<T>接口的时候,多个一个参数,是一个接口我们需要实现其compare()方法排序;
排序List集合里面的元素,例如:
1 /** 2 * 简单的Collection排序 3 */ 4 public static void simpleSort() { 5 List<String> sortElement = new ArrayList<>(); 6 sortElement.add("A"); 7 sortElement.add("D"); 8 sortElement.add("R"); 9 sortElement.add("T"); 10 sortElement.add("F"); 11 System.out.println("未排序之前的List:" + sortElement); 12 Collections.sort(sortElement); 13 System.out.println("排序之后的List:" + sortElement); 14 }
输出结果:
未排序之前的List:[A, D, R, T, F]
排序之后的List:[A, D, F, R, T]
由于String类其实自身已经实现了Comparable接口,Java已经帮我们封装好了,所以我们不需要再实现compareTo()方法;
下面来看下,新建一个Bean,实现Comparable<T>接口,并且实现compareTo()方法来自定义排序。例如:
新建Bean:JavaProgrammer :
1 package com.max.basis; 2 3 import java.io.Serializable; 4 5 /** 6 * Java程序员 7 * @author Max. 8 * @date 2018/7/20 9 */ 10 public class JavaProgrammer implements Comparable<JavaProgrammer>, Serializable { 11 /** 12 * 姓名 13 */ 14 private String name; 15 /** 16 * 工资 17 */ 18 private int wage; 19 /** 20 * 年龄 21 */ 22 private int age; 23 24 @Override 25 public int compareTo(JavaProgrammer o) { 26 // 首先根据年龄排序 27 int sort = this.getAge() - o.getAge(); 28 // 返回值0代表相等,1表示大于,-1表示小于; 29 if (sort == 0) { 30 // 在根据工资排序 31 return this.getWage() - o.getWage(); 32 } 33 return sort; 34 } 35 36 public JavaProgrammer(String name, int wage, int age) { 37 this.name = name; 38 this.wage = wage; 39 this.age = age; 40 } 41 42 public String getName() { 43 return name; 44 } 45 46 public void setName(String name) { 47 this.name = name; 48 } 49 50 public int getWage() { 51 return wage; 52 } 53 54 public void setWage(int wage) { 55 this.wage = wage; 56 } 57 58 public int getAge() { 59 return age; 60 } 61 62 public void setAge(int age) { 63 this.age = age; 64 } 65 }
1 /** 2 * Bean实现Comparable接口,实现compareTo()方法来排序 3 */ 4 public static void sortBeans() { 5 List<JavaProgrammer> sortBeans = new ArrayList<>(); 6 sortBeans.add(new JavaProgrammer("A", 20000, 20)); 7 sortBeans.add(new JavaProgrammer("B", 55000, 21)); 8 sortBeans.add(new JavaProgrammer("C", 65000, 20)); 9 sortBeans.add(new JavaProgrammer("D", 120000, 28)); 10 sortBeans.add(new JavaProgrammer("E", 90000, 23)); 11 Collections.sort(sortBeans); 12 for (JavaProgrammer javaProgrammer : sortBeans) { 13 System.out.println("姓名:" + javaProgrammer.getName() 14 + ",工资:" + javaProgrammer.getWage() 15 + ",年龄:" + javaProgrammer.getAge()); 16 } 17 }
输出结果:
姓名:A,工资:20000,年龄:20 姓名:C,工资:65000,年龄:20 姓名:B,工资:55000,年龄:21 姓名:E,工资:90000,年龄:23 姓名:D,工资:120000,年龄:28
看到上面的Bean,实现了Comparable<T>接口,并且实现compareTo()方法,首先根据年龄大小排序,如果年龄相等,在根据工资大小排序;
再看不在Bean里面实现Comparable<T>接口,在需要用到排序的时候,用Collections.sort(List<T> list, Comparator<? super T> c)方法排序,例如:
新建Bean:TestBean :
1 package com.max.basis; 2 3 import java.io.Serializable; 4 5 /** 6 * 测试类 7 * @author Max. 8 * @date 2018/7/20 9 */ 10 public class TestBean implements Serializable { 11 12 private Integer age; 13 14 private Integer score; 15 16 public TestBean(Integer age, Integer score) { 17 this.age = age; 18 this.score = score; 19 } 20 21 public Integer getAge() { 22 return age; 23 } 24 25 public void setAge(Integer age) { 26 this.age = age; 27 } 28 29 public Integer getScore() { 30 return score; 31 } 32 33 public void setScore(Integer score) { 34 this.score = score; 35 } 36 }
1 /** 2 * 在Collection排序的时候给人Comparator参数 3 */ 4 private static void sortTestBean() { 5 List<TestBean> sortList = new ArrayList<>(); 6 sortList.add(new TestBean(18, 402)); 7 sortList.add(new TestBean(18, 512)); 8 sortList.add(new TestBean(17, 633)); 9 sortList.add(new TestBean(19, 497)); 10 Collections.sort(sortList, new Comparator<TestBean>() { 11 @Override 12 public int compare(TestBean o2, TestBean o1) { 13 int sort = o1.getAge() - o2.getAge(); 14 if (sort == 0) { 15 return o1.getScore() - o2.getScore(); 16 } 17 return sort; 18 } 19 }); 20 for (TestBean testBean : sortList) { 21 System.out.println("年龄:" + testBean.getAge() 22 + ",总分:" + testBean.getScore()); 23 } 24 }
输出结果:
年龄:19,总分:497 年龄:18,总分:512 年龄:18,总分:402 年龄:17,总分:633
注意:如果需要排序或者降序,只需要把o1.getAge() - o2.getAge()两个互换位置就可以了。
然而上面的例子只是对List集合的英文及数字排序,再来看看Collections.sort 中文排序。
public static void sortString(){ List<String> sortStringList = new ArrayList<>(); sortStringList.add("刘邦"); sortStringList.add("项羽"); sortStringList.add("关羽"); sortStringList.add("赵云"); sortStringList.add("诸葛亮"); sortStringList.add("曹操"); sortStringList.add("曹操到"); sortStringList.add("LOL"); sortStringList.add("赵高"); sortStringList.add("10086"); System.out.println("未排序之前的List:" + sortStringList); Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String o1, String o2) { Collator collator = Collator.getInstance(); return collator.getCollationKey(o1).compareTo(collator.getCollationKey(o2)); } }; Collections.sort(sortStringList,comparator); System.out.println("排序之后的List:" + sortStringList); }
输出结果:
未排序之前的List:[刘邦, 项羽, 关羽, 赵云, 诸葛亮, 曹操, 曹操到, LOL, 赵高, 10086]
排序之后的List:[10086, LOL, 曹操, 曹操到, 关羽, 刘邦, 项羽, 赵高, 赵云, 诸葛亮]
排序规则是:数字排在最前,英文字母其次,汉字则按照拼音进行排序。
以上是关于Java中List排序的3种方法的主要内容,如果未能解决你的问题,请参考以下文章