1. 基本类型比较
package compare; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * 基础类型比较 */ public class CollectionsTest1 { public static void main(String[] args) { List<String> strList = new ArrayList<>(); strList.add("15"); strList.add("12"); strList.add("18"); // 字符串排序 Collections.sort(strList); System.out.println("*******字符串排序********"); strList.forEach(System.out::println); System.out.println("*************集合元素“逆向输出(反转)”而非“逆向排序”***********"); Collections.reverse(strList); strList.forEach(System.out::println); List<Integer> intList = new ArrayList<>(); intList.add(15); intList.add(12); intList.add(18); // 整型排序 Collections.sort(intList);// 升序排列 System.out.println("*************整数类型排序***********"); intList.forEach(System.out::println); System.out.println("*************集合元素“逆向输出(反转)”而非“逆向排序”***********"); Collections.reverse(intList); intList.forEach(System.out::println); /** * 为什么基础类型的集合,可以直接调用sort排序,而不需要重新 实现 Comparable 接口类? * 查看底层源码可知: * Sorts the specified list into ascending order, according to the natural ordering of its elements. * All elements in the list must implement the Comparable interface. Furthermore, all elements in the * list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for * any elements e1 and e2 in the list). * 调用该sort()方法的前提条件时,该集合list的类型T必须实现Comparable才行, * 但是基础类型默认都实现了Comparable接口,所以可以直接使用sort方法: * 1.public final class Integer extends Number implements Comparable<Integer> * 2.public final class Double extends Number implements Comparable<Double> * 3.public final class Long extends Number implements Comparable<Long> * ...... * 而String也实现了Comparable接口: * public final class String implements java.io.Serializable, Comparable<String>, CharSequence * 所以都可以直接调用sort方法。 * * 而对于对象而言,其不是基础类型,需要使用Collections.sort()方法时对象需要实现Comparable接口,然后重写compareTo()方法,在方法体中自定义比较规则。 * * 参考链接: * https://www.cnblogs.com/darkings/p/16414530.html * https://blog.csdn.net/u012062455/article/details/78087314 * * 补充: * reverse的意思是反转,而不是降序,只是将原来集合的元素顺序反转一下输出,反转并不意味着降序了,要真正的实现降序,可以先对集合进行升序,然后进行反转,就可以实现降序了。 */ } }
输出结果:
*******字符串排序******** 12 15 18 *************集合元素“逆向输出(反转)”而非“逆向排序”*********** 18 15 12 *************整数类型排序*********** 12 15 18 *************集合元素“逆向输出(反转)”而非“逆向排序”*********** 18 15 12
2. 对象类型比较
2.1 list.stream().sorted()
参考链接:JAVA集合多字段排序方法 - 未月廿三 - 博客园
List<类> list; 代表某集合 //返回 对象集合以类属性一升序排序 list.stream().sorted(Comparator.comparing(类::属性一)); //返回 对象集合以类属性一降序排序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed());//先以属性一升序,对升序结果进行属性一降序 list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()));//以属性一降序 //返回 对象集合以类属性一升序 属性二升序 list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二)); //返回 对象集合以类属性一降序 属性二升序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二));//先以属性一升序,对升序结果进行属性一降序,再进行属性二升序 list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二));//先以属性一降序,再进行属性二升序 //返回 对象集合以类属性一降序 属性二降序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,对升序结果进行属性一降序,再进行属性二降序 list.stream().sorted(Comparator.comparing(类::属性一,Comparator.reverseOrder()).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一降序,再进行属性二降序 //返回 对象集合以类属性一升序 属性二降序 注意两种写法 list.stream().sorted(Comparator.comparing(类::属性一).reversed().thenComparing(类::属性二).reversed());//先以属性一升序,对升序结果进行属性一降序,再进行属性二升序,对前面结果进行属性一降序属性二降序(优先按照属性一降序,属性一相等时再按照属性二降序) list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(类::属性二,Comparator.reverseOrder()));//先以属性一升序,再进行属性二降序
通过以上例子我们可以发现:
-
Comparator.comparing(类::属性一).reversed();
-
Comparator.comparing(类::属性一,Comparator.reverseOrder());
两种排序是完全不一样的,一定要区分开来:
1、是得到排序结果后再排序,
2、是直接进行排序,很多人会混淆导致理解出错,2更好理解,建议使用2
-
Img类
package compare; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateUtil; import lombok.Data; import lombok.ToString; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @Data @ToString public class Img { private Integer id; private Integer sort; private Date createTime; public static void main(String[] args) { List<Img> list = CollUtil.newArrayList(); for (int i = 1; i <= 3; i++) { Img img = new Img(); img.setId(i); img.setSort(i != 1 ? 2 : 1); img.setCreateTime(i == 1 ? DateUtil.offset(new Date(), DateField.MINUTE, 3) : i == 2 ? DateUtil.offset(new Date(), DateField.MINUTE, 1) : DateUtil.offset(new Date(), DateField.MINUTE, 2)); list.add(img); } System.out.println("现有集合:"); list.stream().forEach(item -> System.out.println(item)); System.out.println("使用reversed()排序:"); List<Img> imgList = list.stream().sorted(Comparator.comparing(Img::getSort).thenComparing(Img::getCreateTime).reversed()).collect(Collectors.toList()); imgList.stream().forEach(item -> System.out.println(item)); System.out.println("使用Comparator.reverseOrder()排序:"); List<Img> imgs = list.stream().sorted(Comparator.comparing(Img::getSort).thenComparing(Img::getCreateTime, Comparator.reverseOrder())).collect(Collectors.toList()); imgs.stream().forEach(item -> System.out.println(item)); } }
输出结果:
现有集合: Img(id=1, sort=1, createTime=2022-09-22 20:52:42) Img(id=2, sort=2, createTime=2022-09-22 20:50:42) Img(id=3, sort=2, createTime=2022-09-22 20:51:42) 使用reversed()排序: Img(id=3, sort=2, createTime=2022-09-22 20:51:42) Img(id=2, sort=2, createTime=2022-09-22 20:50:42) Img(id=1, sort=1, createTime=2022-09-22 20:52:42) 使用Comparator.reverseOrder()排序: Img(id=1, sort=1, createTime=2022-09-22 20:52:42) Img(id=3, sort=2, createTime=2022-09-22 20:51:42) Img(id=2, sort=2, createTime=2022-09-22 20:50:42)
2.2 Collections.sort()
@Override public int compareTo(Object o) { return 0; }
方法原理:利用当前对象和传入的目标对象进行比较,通过返回值,决定顺序。
(1)当返回值是 “-1”,代表从大到小排序;
(2)当返回值是 “1”,代表从小到大排序;
(3)当返回值是 “0”,两对象相等;
-
User
package compare; import lombok.*; import lombok.experimental.Accessors; @Data @Getter @Setter @NoArgsConstructor @AllArgsConstructor @ToString @Accessors(chain = true) public class User implements Comparable{ private String name; private Integer age; @Override public int compareTo(Object o) { // 1.单条件比较 // if(o instanceof User){ // User user = (User)o; // return this.name.compareTo(user.getName());// 按照name升序排列 // return this.age.compareTo(user.getAge());// 按照age升序排列 return this.age - user.getAge();// 按照age升序排列 // } // // 2.多条件比较 if(o instanceof User){ User user = (User)o; if(this.age>user.getAge()){ return 1; }else if(this.age<user.getAge()){ return -1; }else{ return this.name.compareTo(user.getName()); } } throw new ClassCastException("类型转换异常"); } }
-
测试
package compare; import java.util.*; /** * 对象类型比较:根据对象的某些属性来排序 */ public class CollectionsTest2 { public static void main(String[] args) { /** * 参考链接: * https://blog.csdn.net/qq_43842093/article/details/122934159 * https://blog.csdn.net/glenshappy/article/details/125320532 * java集合的工具类Collections中提供了两种排序的方法,分别是: * 1.Collections.sort(List list):自然排序 * 要求参与排序的对象(包含基本属性、getter/setter方法、有参/无参构造方法、toString方法)实现Comparable接口,并重写其中的compareTo()方法,方法体中定义对象的大小比较原则 * * 2.Collections.sort(List list,Comparator c) * 也叫定制排序/自定义排序,需编写匿名内部类,先new一个Comparator接口的比较器对象c,同时实现compare()其方法; * 然后将比较器对象c传给Collections.sort()方法的参数列表中,实现排序功能。 * * 第二种方法说明第一种方法不够灵活,实体类实现了comparable接口后,会增加耦合, * 如果在项目中不同的位置需要根据不同的属性调用排序方法时,需要反复修改比较规则(按name还是按age),二者只能选择其一,会起冲突, * 第二种方法就很好地解决了这个问题,在需要的地方创建个内部类的实例,重写其比较方法即可。 * * */ List<User> userList = new ArrayList<>(); userList.add(new User("tom",18)); userList.add(new User("jack",20)); userList.add(new User("rose",15)); userList.add(new User("jerry",17)); userList.add(new User("liming",17)); userList.add(new User("rose",19)); System.out.println("------------排序前:-----------"); userList.forEach(System.out::println); List<User> userList1 = userList; List<User> userList2 = userList; List<User> userList3= userList; List<User> userList4= userList; List<User> userList5= userList; // 1.测试Collections.sort(List list)按照自然规则排序:单一规则 Collections.sort(userList);// 更换name或age比较规则时需要在重写的compareTo()方法中修改方法体,只能定义单一比较规则 System.out.println("------------Collections.sort(List list)排序后:--------------"); userList.forEach(System.out::println); System.out.println("------------使用迭代器对实现Comparable接口对象集合进行输出,效果与Collections.sort(List list)一致-------------------"); Iterator<User> iterator = userList3.iterator(); while (iterator.hasNext()){ User next = iterator.next(); System.out.println(next); } // 2.1 测试Collections.sort(List list,Comparator c)按age自定义排序:单一规则 // Collections.sort(userList1, new Comparator<User>() { // @Override // public int compare(User o1, User o2) { // return o1.getAge() - o2.getAge(); // } // }); // 简化 Collections.sort(userList1, (o1,o2)-> o1.getAge() - o2.getAge());// o1.getAge() - o2.getAge():升序排列,o2.getAge() - o1.getAge():降序排列 System.out.println("-------------Collections.sort(List list)按age升序排列后:-----------------"); userList1.forEach(System.out::println); // 2.2 测试Collections.sort(List list,Comparator c)按name自定义排序:单一规则 Collections.sort(userList2, (e1,e2)->e1.getName().compareTo(e2.getName()));// e1.getName().compareTo(e2.getName()):升序排列,e1.getName().compareTo(e2.getName()):降序排列 System.out.println("-------------Collections.sort(List list)按name升序排列后:-----------------"); userList2.forEach(System.out::println); // 2.3 测试Collections.sort(List list,Comparator c)按name自定义排序:多规则 Collections.sort(userList4,((Comparator<User>)(o1, o2) -> { return o1.getAge() - o2.getAge();// 升序 }).thenComparing((o1, o2) -> { return o1.getName().compareTo(o2.getName());// 升序 })); System.out.println("-------------Collections.sort(List list)先按age升序再按name升序排列后:-----------------"); userList4.forEach(System.out::println); // 2.4 测试Collections.sort(List list,Comparator c)按name自定义排序:多规则 Collections.sort(userList5, new Comparator<User>() { @Override public int compare(User o1, User o2) { if(o1.getAge()>o2.getAge()){ return 1; }else if(o1.getAge()<o2.getAge()){ return -1; }else{ return o1.getName().compareTo(o2.getName()); } } }); System.out.println("-------------Collections.sort(List list)先按age升序再按name升序排列后:-----------------"); userList5.forEach(System.out::println); } }
输出结果:
------------排序前:----------- User(name=tom, age=18) User(name=jack, age=20) User(name=rose, age=15) User(name=jerry, age=17) User(name=liming, age=17) User(name=rose, age=19) ------------Collections.sort(List list)排序后:-------------- User(name=rose, age=15) User(name=jerry, age=17) User(name=liming, age=17) User(name=tom, age=18) User(name=rose, age=19) User(name=jack, age=20) ------------使用迭代器对实现Comparable接口对象集合进行输出,效果与Collections.sort(List list)一致------------------- User(name=rose, age=15) User(name=jerry, age=17) User(name=liming, age=17) User(name=tom, age=18) User(name=rose, age=19) User(name=jack, age=20) -------------Collections.sort(List list)按age升序排列后:----------------- User(name=rose, age=15) User(name=jerry, age=17) User(name=liming, age=17) User(name=tom, age=18) User(name=rose, age=19) User(name=jack, age=20) -------------Collections.sort(List list)按name升序排列后:----------------- User(name=jack, age=20) User(name=jerry, age=17) User(name=liming, age=17) User(name=rose, age=15) User(name=rose, age=19) User(name=tom, age=18) -------------Collections.sort(List list)先按age升序再按name升序排列后:----------------- User(name=rose, age=15) User(name=jerry, age=17) User(name=liming, age=17) User(name=tom, age=18) User(name=rose, age=19) User(name=jack, age=20) -------------Collections.sort(List list)先按age升序再按name升序排列后:----------------- User(name=rose, age=15) User(name=jerry, age=17) User(name=liming, age=17) User(name=tom, age=18) User(name=rose, age=19) User(name=jack, age=20)