java list排序
1、简介
这个和数组的排序又不一样了。
其实Java针对数组和List的排序都有实现,对数组而言,你可以直接使用Arrays.sort,对于List和Vector而言,你可以使用Collections.sort方法。
Java API针对集合类型的排序提供了2个方法:
java.util.Collections.sort(java.util.List) java.util.Collections.sort(java.util.List, java.util.Comparator)
如果集合里面的元素都是相同类型的,并且实现了Comparable接口,那么可以直接调用第一个方法。
如果你有其它的排序的想法,比如你不想按照自然排序进行,还可以传一个Comparator过去,比如反向。
元素不相同的情况比较复杂,可以暂时不用考虑。
2、通过实现Comparable接口来实现list的排序
假如现在我们有一个Person类的list集合,要让其按照一个Order属性进行排序,我们可以让Person类实现Comparable接口,重写其CompareTo方法即可。具体实现如下:
1)、Person实体类
public class Person implements Comparable<Person> { private String name; private Integer order; /** * @return the name */ public String getName() { return name; } /** * @param name * the name to set */ public void setName(String name) { this.name = name; } /** * @return the order */ public Integer getOrder() { return order; } /** * @param order * the order to set */ public void setOrder(Integer order) { this.order = order; } @Override public int compareTo(Person arg0) { return this.getOrder().compareTo(arg0.getOrder()); //这里定义你排序的规则。 } }
通过重写Comparable接口的compareTo方法,可以让程序按照我们想要的排列方式进行排序,如:这里我让Person按照order属性升序排序。
2)、测试类
public static void main(String[] args) { //初始化数据 List<Person> listA = new ArrayList<Person>(); Person p1 = new Person(); Person p2 = new Person(); Person p3 = new Person(); p1.setName("name1"); p1.setOrder(1); p2.setName("name2"); p2.setOrder(2); p3.setName("name3"); p3.setOrder(3); listA.add(p2); listA.add(p1); listA.add(p3); //排序 Collections.sort(listA); //打印排序后的Person for (Person p : listA) { System.out.println(p.getName()); } }
3)、结果:
name1 name2 name3
3、通过重载Collections.sort方法
直接重载java.util.Collections.sort(java.util.List, java.util.Comparator) 方法。可以灵活的修改我们排序的方式,具体实现如下:
1)、Person实体类
和上面的类相同,但没实现Comparable接口
public class Person { private String name; private Integer order; /** * @return the name */ public String getName() { return name; } /** * @param name * the name to set */ public void setName(String name) { this.name = name; } /** * @return the order */ public Integer getOrder() { return order; } /** * @param order * the order to set */ public void setOrder(Integer order) { this.order = order; } }
2)、测试类
public static void main(String[] args) { List<Person> listA = new ArrayList<Person>(); Person p1 = new Person(); Person p2 = new Person(); Person p3 = new Person(); p1.setName("name1"); p1.setOrder(1); p2.setName("name2"); p2.setOrder(2); p3.setName("name3"); p3.setOrder(3); listA.add(p2); listA.add(p1); listA.add(p3); //直接在这里添加我们的排序规则 Collections.sort(listA, new Comparator<Person>() { public int compare(Person arg0, Person arg1) { return arg0.getOrder().compareTo(arg1.getOrder()); } }); for (Person p : listA) { System.out.println(p.getName()); } }
从上面看到,直接在Conllections.sort()方法中重写了一个Comparator接口,可以在不同的地方使用Person集合的不同排序方法。如上面还是按照Person的order属性升序排列,我只要改写该方法,就可以在其他地方按照其他的规则对我的list集合进行排序,但是这样子代码看起来会比前面的那种方式繁琐。
3)、结果
name1 name2 name3
致谢:感谢您的阅读!
4.扩展:按照两个字段排序
比如先按照名字排序,如果名字相同,按照小名排序;例子如下:
package com.cy.model; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Student implements Comparable<Student>{ private int id; private String name; //名字 private String sname; //小名 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Student(int id, String name, String sname) { super(); this.id = id; this.name = name; this.sname = sname; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", sname=" + sname + "]"; } /** * student类的排序方法 * 先按照name排序,如果name相同按照sname排序 */ @Override public int compareTo(Student o) { int r1 = this.getName().compareToIgnoreCase(o.getName()); int r2 = this.getSname().compareToIgnoreCase(o.getSname()); return r1>0?1: r1<0?-1: r2>0?1: r2<0?-1:0; } //测试程序 public static void main(String[] args) { Student s1 = new Student(2,"zhangsan","z"); Student s2 = new Student(1, "zhangsan","b"); Student s3 = new Student(3, "zhangsan","y"); Student s4 = new Student(0, "lisi","s"); Student s5 = new Student(5, "wangwu","w"); Student s6 = new Student(10, "wangwu","xx"); Student s7 = new Student(8, "aming","ming"); List<Student> list = new ArrayList<Student>(); list.add(s1);list.add(s2);list.add(s3);list.add(s4); list.add(s5);list.add(s6);list.add(s7); Collections.sort(list); for(Student s : list){ System.out.println(s); } } }
打印:
Student [id=8, name=aming, sname=ming] Student [id=0, name=lisi, sname=s] Student [id=5, name=wangwu, sname=w] Student [id=10, name=wangwu, sname=xx] Student [id=1, name=zhangsan, sname=b] Student [id=3, name=zhangsan, sname=y] Student [id=2, name=zhangsan, sname=z]
5.按照中文拼音排序:
有的时候我们需要按照中文拼音来排序,代码如下:
package com.test.list;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* Description:中文排序测试
* Author: chengyu
* Created: 2021-08-17 10:12
*/
public class TestListSort {
public static void main(String[] args) {
List<map<string, string="">> list = initData();
System.out.println(list);
//按照产品名称进行排序
Collections.sort(list, new Comparator<map<string, string="">>() {
@Override
public int compare(Map<string, string=""> o1, Map<string, string=""> o2) {
String prdName1 = o1.get( "prdName" );
String prdName2 = o2.get( "prdName" );
return Collator.getInstance(Locale.CHINA).compare(prdName1, prdName2);
}
});
System.out.println(list);
Collections.sort(list, new Comparator<map<string, string="">>() {
@Override
public int compare(Map<string, string=""> o1, Map<string, string=""> o2) {
String prdName1 = o1.get( "prdName" );
String prdName2 = o2.get( "prdName" );
return Collator.getInstance(Locale.SIMPLIFIED_CHINESE).compare(prdName1, prdName2);
}
});
System.out.println(list);
}
public static List<map<string, string="">> initData(){
List<map<string, string="">> list = new ArrayList<>();
Map<string, string=""> m1 = new HashMap<>();
m1.put( "prdId" , "majorAcctSet" );
m1.put( "prdName" , "默认账户设置" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "delAuthConfig" );
m1.put( "prdName" , "审批流程删除" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "processTask" );
m1.put( "prdName" , "交易授权" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "AddCifRole" );
m1.put( "prdName" , "新增企业操作员角色" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "MCMarginPaymentRefund" );
m1.put( "prdName" , "产权保证金退款" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "UpdateCifRole" );
m1.put( "prdName" , "修改企业操作员角色" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "acctDel" );
m1.put( "prdName" , "客户账户解挂" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "UserShortMenuDel" );
m1.put( "prdName" , "快捷菜单删除" );
list.add(m1);
m1 = new HashMap<>();
m1.put( "prdId" , "addCifAcctBBMS" );
m1.put( "prdName" , "客户账户加挂" );
list.add(m1);
return list;
}
} </string,></map<string,></map<string,></string,></string,></map<string,></string,></string,></map<string,></map<string,>
上面两种排序方式都可以。排序结果一样,还没发现区别。
6.Collections.sort()和list.stream.sorted()的区别
Collection sort()和stream().sorted()
我的理解是:
1)看api接口,Collections.sort(List<T extends Comparable> list)和Collections.sort(List, Comparator c)其实都是调的是list方法的list.sort(null)和list.sort(c),所以不管是用Collections.sort还是list本身自己的list.sort本质上是一样的。
2)Collections.sort()可以直接给list排序,没有返回值。而stream.sorted()返回值是Stream,需要collect(Collectors.toList())返回后赋值。
3)stream.sorted()可以链式写法,搭配stream的filter、map的方法一齐使用。
7.Collections.sort、stream.sorted排序时间比较
参考:
collections.sort vs treeSet sort vs java8 stream.sorted
为什么list.sort()比Stream().sorted()更快
解密排序之争:原生List VS 流行Stream,谁更高效
结论:
我们可以看到Collections.sort比TreeSet的性能要更好些,分析后可能是由于TreeSet在红黑树中新插入节点也需要消耗一定的时间,且每次插入后需要对原有的集合进行修改以使得新集合底层仍然是红黑树。 而且TreeSet只能使用一个比较器,但你却可以为Collection提供不同的比较器。Java8的流排序的效率相比前两个就有点低了,但Java8的流排序可以省去构造冗长的比较器,编写更简洁的代码。
8.Comparator和Comparable这两个接口的区别:
`Comparator` 和 `Comparable` 都是 Java 中用于比较对象的接口,但它们在使用方式、设计理念和灵活性上有显著的区别。以下是它们的详细对比:
1. 核心区别
| 特性 | Comparable |
Comparator |
|---|---|---|
| 包位置 | java.lang.Comparable |
java.util.Comparator |
| 比较逻辑位置 | 在类内部实现,由类自身定义比较规则 | 在类外部实现,独立定义比较规则 |
| 方法 | int compareTo(T o) |
int compare(T o1, T o2) |
| 使用场景 | 自然排序(默认排序规则) | 定制排序(多种排序规则) |
| 修改权限 | 需要修改类源代码 | 无需修改类源代码 |
| 灵活性 | 较低(只能有一种比较逻辑) | 较高(可以定义多个比较器) |
2. 详细解释
Comparable 接口:
类实现 Comparable` 接口,表示该类的对象本身具有可比较性。方法:compareTo(T o),比较当前对象与参数对象。
特点:自然排序:定义该类对象的默认排序规则。
侵入性强:必须修改类的源代码。
只能有一种比较逻辑(因为只有一个 compareTo 方法)。
示例:
public class Student implements Comparable<Student> {
private String name;
private int age;
// 构造方法、getter/setter 省略
@Override
public int compareTo(Student other) {
return this.age - other.age; // 按年龄升序排序
}
}
// 使用
Collections.sort(studentList); // 自动按年龄排序
Comparator 接口:
定义:单独定义一个比较器类(或匿名类),用于比较两个对象。
方法:compare(T o1, T o2),比较两个参数对象。
特点:定制排序:可以为同一个类定义多种排序规则。非侵入性:无需修改类源代码。灵活性高:可以随时创建新的比较器。
示例:
public class Student {
private String name;
private int age;
// 构造方法、getter/setter 省略
}
// 按年龄升序
Comparator<Student> ageComparator = new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1.getAge() - s2.getAge();
}
};
// 按姓名升序
Comparator<Student> nameComparator = (s1, s2) -> s1.getName().compareTo(s2.getName());
// 使用
Collections.sort(studentList, ageComparator); // 按年龄排序
Collections.sort(studentList, nameComparator); // 按姓名排序
3.综合对比表
| 对比项 | Comparable |
Comparator |
|---|---|---|
| 排序逻辑位置 | 在类内部 | 在类外部(独立类或匿名类) |
| 接口方法 | compareTo(T o) |
compare(T o1, T o2) |
| 调用方式 | obj1.compareTo(obj2) |
comparator.compare(obj1, obj2) |
| 常用方法 | Collections.sort(List) |
Collections.sort(List, Comparator) |
| Java 8+ 特性 | 无特殊支持 | 支持 Lambda 表达式、链式调用(thenComparing) |
| 适用场景 | 类的自然排序(如 String、Integer 的默认排序) | 多种排序需求、无法修改源码的类 |
4.选择建议
使用 `Comparable` 当:
- 类有明确的自然排序规则(如按 ID、时间等)。
- 排序逻辑固定且不会变化。
- 你有权修改类的源代码。
使用 `Comparator` 当:
- 需要多种排序方式(如按年龄、姓名、成绩等)。
- 排序逻辑需要灵活切换。
- 无法修改类源代码(如第三方库的类)。
- 需要使用 Lambda 表达式简化代码(Java 8+)。
5.Java 8+ 增强
`Comparator` 接口在 Java 8 后增加了许多实用方法,使排序更加简洁:
// 使用 Comparator.comparing 简化
Comparator<Student> ageComparator = Comparator.comparing(Student::getAge);
Comparator<Student> nameComparator = Comparator.comparing(Student::getName);
// 链式排序:先按年龄,再按姓名
Comparator<Student> complexComparator = Comparator
.comparing(Student::getAge)
.thenComparing(Student::getName);
// 使用
Collections.sort(studentList, complexComparator);
总结:
Comparable:内部比较器,定义对象的默认排序规则(自然排序)。
Comparator:外部比较器,定义对象的定制排序规则,更加灵活。
两者相辅相成,在实际开发中应根据具体需求选择合适的方式。
---
浙公网安备 33010602011771号