List集合排序总结
目录
问题现象
解决方法:
1、Collections.sort(java对象)
2、Collections.sort(java对象集合, new Comparator<>() {});
拓展:
3、list.stream().sorted()
拓展:
总结:
4、List排序
4.1、List的单条件升序(默认)排序
4.2、List的单条件降序排序
4.3、List的多条件排序
问题现象
今天在项目中相对List集合进行按需求的排序,因此打算总结一下各种情况下的List排序的代码写法?
解决方法:
自己总结了以下,list集合的排序主要有以下几种排序方式:
1、Collections.sort(java对象)
这种方式需要满足以下条件:
1.1、list集合中元素的数据类型是一个java对象;
1.2、该java对象必须实现Comparable类;
1.3、重写compareTo方法;
其中 compareTo 方法用于指示当前元素与其他元素的比较规则,一般都是以 a - b 的形式返回int类型,表示排序规则为从 a 到 b 排序,其逻辑理解就是:如果compareTo方法返回值小于0,则当前元素往前放,大于0,则往后放。
Student实体类:
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Student implements Comparable<Student> {private String name;private int age;@Overridepublic int compareTo(Student stu) {return getAge() - stu.getAge();}
}
测试:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class TestUtil {public static void main(String[] args) {Student stu1=new Student("小米",1);Student stu2=new Student("小王",2);Student stu3=new Student("小明",3);List<Student> list=new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("排序后:");Collections.sort(list);System.out.println(list);}
}
打印结果:
2、Collections.sort(java对象集合, new Comparator<>() {});
这种方式与需要满足以下条件:
1.1、list集合中元素的数据类型是一个java对象;
1.2、重写compare方法;
Comparator 和 Comparable 的区别和理解:
Comparator 可以看成是外部比较器,因为它是先有list集合,然后再对list集合用比较器去排序;
Comparable 可以看成是内部比较器,因为它是直接在java对象实现类添加了比较器,因此是先有比较器,然后再对list集合用比较器去排序;
从上面两点,也可以推测出 Comparable 的排序算法的效率应该是比 Comparator 要高效的。
Comparator :使用了匿名内部类来构建了一个Comparator比较器对象,从而实现排序,优点是:不需要在创建java对象时,实现 Comparable 接口,缺点是效率比 Comparable 要低一些。
Student实体类:
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Student{private String name;private int age;}
测试:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;public class TestUtil {public static void main(String[] args) {Student stu1 = new Student("小米", 1);Student stu2 = new Student("小王", 2);Student stu3 = new Student("小明", 3);List<Student> list = new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("排序后:");Collections.sort(list, new Comparator<Student>() {@Overridepublic int compare(Student stu1, Student stu2) {return stu1.getAge() - stu2.getAge();}});System.out.println(list);}
}
打印结果:
拓展:
根据 JAVA8 的 lambda 表达式上面Compartor比较器的代码可以简写成以下代码:
Collections.sort(list, (stu11, stu21) -> stu11.getAge() - stu21.getAge());
再进一步简化成如下代码:
Collections.sort(list, Comparator.comparingInt(Student::getAge));
或Collections.sort(list, Comparator.comparing(Student::getAge));
通过查询 comparing开头的方法,可以看见:
经过我的测试发现comparing兼容了下面三种基于整型数据的方法:
显然用comparing很省事,但是一般兼容性越高,效率也就越低,可以推测出comparing方法内部肯定是有一重判断了参数的数据类型的逻辑,这会降低代码执行效率;因此,如果是整型数据的话,建议使用上面三种与数据类型对应的方法,而如果是字符串的话,就使用comparing。
简化后:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;public class TestUtil {public static void main(String[] args) {Student stu1 = new Student("小米", 1);Student stu2 = new Student("小王", 2);Student stu3 = new Student("小明", 3);List<Student> list = new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("排序后:");Collections.sort(list, Comparator.comparingInt(Student::getAge));System.out.println(list);}
}
打印结果:
可以看出这是升序排序的,那么如何降序呢?
由于降序=升序的倒序,所以可以使用倒序的方法【.reversed()】实现降序:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;public class TestUtil {public static void main(String[] args) {Student stu1 = new Student("小米", 1);Student stu2 = new Student("小王", 2);Student stu3 = new Student("小明", 3);List<Student> list = new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("排序后:");Collections.sort(list, Comparator.comparingInt(Student::getAge));System.out.println(list);System.out.println("倒序后:");Collections.sort(list, Comparator.comparingInt(Student::getAge).reversed());System.out.println(list);}
}
打印结果:
多条件排序:
Student实体类:
@Data
@AllArgsConstructor
public class Student{private String name;private int age;private double grade;private int tall;}
测试:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;public class TestUtil {public static void main(String[] args) {Student stu1 = new Student("小米", 20, 95.0, 175);Student stu2 = new Student("小王", 20, 90.5, 175);Student stu3 = new Student("小明", 20, 90.0, 180);List<Student> list = new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("排序后:");Collections.sort(list, Comparator.comparingInt(Student::getTall));System.out.println(list);System.out.println("倒序后:");Collections.sort(list, Comparator.comparingInt(Student::getTall).reversed());System.out.println(list);System.out.println("1.按年龄升序、分数升序、身高升序排序:");Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall));System.out.println(list);System.out.println("2.按年龄升序、分数升序、身高降序序排序:");Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall).reversed());System.out.println(list);System.out.println("3.按年龄升序、分数降序、身高升序排序:");Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall));System.out.println(list);System.out.println("4.按年龄升序、分数降序、身高降序序排序:");Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall).reversed());System.out.println(list);System.out.println("5.按年龄升序、身高升序、分数升序排序:");Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade));System.out.println(list);System.out.println("6.按年龄升序、身高升序、分数降序序排序:");Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade).reversed());System.out.println(list);System.out.println("7.按年龄升序、身高降序、分数升序排序:");Collections.sort(list, Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).reversed().thenComparingDouble(Student::getGrade));System.out.println(list);System.out.println("8.按年龄升序、身高降序、分数降序序排序:");Collections.sort(list, Comparator.comparing(Student::getAge).thenComparing(Student::getGrade).reversed().thenComparing(Student::getTall).reversed());System.out.println(list);}
}
打印结果:
3、list.stream().sorted()
JAVA8 之后,引入了stream流操作,可以极大提高集合的链式操作效率,关于stream流操作不太清楚的小伙伴,可以自行查阅资料,比较简单,这里就不再拓展了;
这里要提的是stream流操作中的 sorted()方法可以用于排序,其逻辑原理和上面第二种 Comparator 的排序方式是一样的。
这种方式与需要满足以下条件:
1.1、list集合中元素的数据类型是一个java对象;
1.2、引入stream流操作规范;
优点:排序算法效率高。
Student实体类:
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Student{private String name;private int age;}
测试:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;public class TestUtil {public static void main(String[] args) {Student stu1 = new Student("小米", 1);Student stu2 = new Student("小王", 2);Student stu3 = new Student("小明", 3);List<Student> list = new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("排序后:");list = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());System.out.println(list);}
}
打印结果:
同样的以使用倒序的方法【.reversed()】实现降序:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;public class TestUtil {public static void main(String[] args) {Student stu1 = new Student("小米", 1);Student stu2 = new Student("小王", 2);Student stu3 = new Student("小明", 3);List<Student> list = new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("排序后:");list = list.stream().sorted(Comparator.comparing(Student::getAge)).collect(Collectors.toList());System.out.println(list);System.out.println("倒序后:");list = list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());System.out.println(list);}
}
打印结果:
拓展:
很多使用不仅需要对单一字段进行排序,还需要多个字段排序,因此多条件排序很重要!
多条件排序:
Student实体类:
import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class Student{private String name;private int age;private double grade;private int tall;}
测试:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;public class TestUtil {public static void main(String[] args) {Student stu1 = new Student("小米", 20, 95.0, 175);Student stu2 = new Student("小王", 20, 90.5, 175);Student stu3 = new Student("小明", 20, 90.0, 180);List<Student> list = new ArrayList<>();list.add(stu2);list.add(stu1);list.add(stu3);System.out.println("排序前:");System.out.println(list);System.out.println("1.按年龄升序、分数升序、身高升序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall)).collect(Collectors.toList());System.out.println(list);System.out.println("2.按年龄升序、分数升序、身高降序序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).thenComparingInt(Student::getTall).reversed()).collect(Collectors.toList());System.out.println(list);System.out.println("3.按年龄升序、分数降序、身高升序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall)).collect(Collectors.toList());System.out.println(list);System.out.println("4.按年龄升序、分数降序、身高降序序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingDouble(Student::getGrade).reversed().thenComparingInt(Student::getTall).reversed()).collect(Collectors.toList());System.out.println(list);System.out.println("5.按年龄升序、身高升序、分数升序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade)).collect(Collectors.toList());System.out.println(list);System.out.println("6.按年龄升序、身高升序、分数降序序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).thenComparingDouble(Student::getGrade).reversed()).collect(Collectors.toList());System.out.println(list);System.out.println("7.按年龄升序、身高降序、分数升序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).reversed().thenComparingDouble(Student::getGrade)).collect(Collectors.toList());System.out.println(list);System.out.println("8.按年龄升序、身高降序、分数降序序排序:");list = list.stream().sorted(Comparator.comparingInt(Student::getAge).thenComparingInt(Student::getTall).reversed().thenComparingDouble(Student::getGrade).reversed()).collect(Collectors.toList());System.out.println(list);}
}
打印结果:
总结:
推荐使用第三种排序方法,因为stream流操作排序效率最高。
4、List<JSONObject>排序
这个其实才是这篇文章的重点,很多时候为了方便,我们会用到JSONObject或者Map对象去接收数据库返回的结果集;
1、例如当数据库表过多的时候,我们并不想为每个表都创建一个java实体类去接收数据;
2、尤其是当我们想动态的查询出自己想要的数据,而结果中的字段名很可能并不是固定的;
3、当然还有很多其他的复杂情况。。。
当我们使用的这一类不是由java实体类组成的List集合的时候,上面的那三种方法显然是未必适用的,于是为了应对这种情况下的排序需求,经过我的测试,总结出了下面3种情况和方法:
4.1、List<JSONObject>的单条件升序(默认)排序
大多数情况下,我们需要排序的时候,都是单条件排序,所以这是最基本的排序方法,基本上和第三种排序方式(list.stream().sorted())中的单条件排序的写法很类似,所以比较简单。
测试:
public class TestDemoUtil {public static void main(String[] args) {List<JSONObject> list = new ArrayList<>();JSONObject jsonObject1 = new JSONObject();JSONObject jsonObject2 = new JSONObject();JSONObject jsonObject3 = new JSONObject();jsonObject1.put("name", "小米");jsonObject1.put("age", 20);jsonObject1.put("grade", 95.0);jsonObject1.put("tail", 175);jsonObject2.put("name", "小王");jsonObject2.put("age", 20);jsonObject2.put("grade", 90.5);jsonObject2.put("tail", 175);jsonObject3.put("name", "小明");jsonObject3.put("age", 20);jsonObject3.put("grade", 90.0);jsonObject3.put("tail", 180);list.add(jsonObject1);list.add(jsonObject2);list.add(jsonObject3);System.out.println("排序前:");System.out.println(list);System.out.println("按成绩升序排序后:");list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade"))).collect(Collectors.toList());System.out.println(list);}
}
打印结果:
4.2、List<JSONObject>的单条件降序排序
需要注意的是,和上面提到的第三种排序方式(list.stream().sorted())不同,在对集合进行降序排序的时候,无法直接在链式链式调用后面加上【.reversed()】来实现降序了;经过测试发现list.stream().sorted()对于JSONObject这一类非自定义的java对象无法完美是使用链式调用了,原因很可能是因为JSONObject这一类对象没有确定属性的getter/setter方法,所以下面这种写法会在编译的时候报错:
list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade")).reversed()).collect(Collectors.toList());
猜测原因应该是因为在链式调用中 getDoubleValue 会被识别为 JSONObject对象中 doubleValue属性对应的 getter方法,而该对象根本没有这个属性,所以就报错了,所以还是那句话链式调用的规则,并不适用于没有确定属性的这一类对象。
所以可以使用下面这种写法来解决降序的问题:
测试:
public class TestDemoUtil {public static void main(String[] args) {List<JSONObject> list = new ArrayList<>();JSONObject jsonObject1 = new JSONObject();JSONObject jsonObject2 = new JSONObject();JSONObject jsonObject3 = new JSONObject();jsonObject1.put("name", "小米");jsonObject1.put("age", 20);jsonObject1.put("grade", 95.0);jsonObject1.put("tail", 175);jsonObject2.put("name", "小王");jsonObject2.put("age", 20);jsonObject2.put("grade", 90.5);jsonObject2.put("tail", 175);jsonObject3.put("name", "小明");jsonObject3.put("age", 20);jsonObject3.put("grade", 90.0);jsonObject3.put("tail", 180);list.add(jsonObject1);list.add(jsonObject2);list.add(jsonObject3);System.out.println("排序前:");System.out.println(list);System.out.println("按成绩升序排序后:");list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade"))).collect(Collectors.toList());System.out.println(list);System.out.println("按成绩降序排序后:");list = list.stream().sorted((o1, o2) -> o2.getDoubleValue("grade") - o1.getDoubleValue("grade") > 0 ? 1 : -1).collect(Collectors.toList());System.out.println(list);}
}
打印结果:
4.3、List<JSONObject>的多条件排序
多条件排序是重点,虽然很多时候我们只需要单条件排序;但多条件排序的写法才是重点,因为这种写法是最基础的,也是兼容最强的。
测试:
public class TestDemoUtil {public static void main(String[] args) {List<JSONObject> list = new ArrayList<>();JSONObject jsonObject1 = new JSONObject();JSONObject jsonObject2 = new JSONObject();JSONObject jsonObject3 = new JSONObject();jsonObject1.put("name", "小米");jsonObject1.put("age", 20);jsonObject1.put("grade", 95.0);jsonObject1.put("tail", 175);jsonObject2.put("name", "小王");jsonObject2.put("age", 20);jsonObject2.put("grade", 90.5);jsonObject2.put("tail", 175);jsonObject3.put("name", "小明");jsonObject3.put("age", 20);jsonObject3.put("grade", 90.0);jsonObject3.put("tail", 180);list.add(jsonObject1);list.add(jsonObject2);list.add(jsonObject3);System.out.println("排序前:");System.out.println(list);System.out.println("按成绩排序后:");list = list.stream().sorted(Comparator.comparingDouble(o -> o.getDoubleValue("grade"))).collect(Collectors.toList());System.out.println(list);System.out.println("1.按年龄升序、分数升序、身高升序排序:");list = list.stream().sorted((o1, o2) -> {int value = o1.getIntValue("age") - o2.getIntValue("age");if ( value == 0 ) {double v = o1.getDoubleValue("grade") - o2.getDoubleValue("grade");if ( v == 0.0 ) {return o1.getIntValue("tail") - o2.getIntValue("tail");}return v > 0.0 ? 1 : -1;}return value;}).collect(Collectors.toList());System.out.println(list);System.out.println("2.按年龄升序、分数降序、身高升序排序:");list = list.stream().sorted((o1, o2) -> {int value = o1.getIntValue("age") - o2.getIntValue("age");if ( value == 0 ) {double v = o2.getDoubleValue("grade") - o1.getDoubleValue("grade");if ( v == 0.0 ) {return o1.getIntValue("tail") - o2.getIntValue("tail");}return v > 0.0 ? 1 : -1;}return value;}).collect(Collectors.toList());System.out.println(list);System.out.println("3.按年龄升序、身高升序、分数降序排序:");list = list.stream().sorted((o1, o2) -> {int value = o1.getIntValue("age") - o2.getIntValue("age");if ( value == 0 ) {value = o1.getIntValue("tail") - o2.getIntValue("tail");if ( value == 0 ) {return o2.getDoubleValue("grade") - o1.getDoubleValue("grade") > 0.0 ? 1 : -1;}return value;}return value;}).collect(Collectors.toList());System.out.println(list);}
}
上面的代码可以通过提取公共方法,来提高代码复用率,由于和文章主题无关,这里就不进一步优化了。
打印结果:
List集合排序总结相关推荐
- java怎么给list集合排序_java list集合排序按某一属性排序操作
我就废话不多说了,大家还是直接看代码吧~ public List sortList(List list){ Collections.sort(list, new Comparator(){ @Over ...
- 【Java基础篇】集合排序
所谓集合排序是指对集合内的元素进行排序. 集合工具类Collections中提供了两种排序算法,分别是: Collections.sort(List list) Collections.sort(Li ...
- java8新特性:对map集合排序
一.简单介绍Map 在讲解Map排序之前,我们先来稍微了解下map,map是键值对的集合接口,它的实现类主要包括:HashMap, TreeMap, Hashtable以及LinkedHashMap等 ...
- java 集合排序方法_java集合排序方法sort的使用
转自 http://blog.csdn.net/a1165117473/article/details/6965652 /* * To change this template, choose To ...
- 写了一个对象集合排序的类
写了一个对象集合排序的类 废话不多说,首先是定义一个对象实体类 class Entity { public Entity() {} pr ...
- 使用stream流进行集合排序取最大值,根据集合中的bigdemal属性排序(正序反序)并取最大值
业务: 求折线图的UPH图相关数据,前端动态修改纵轴的峰值,需要后端获取最大值 1)根据集合某个属性(业务以bigdecimal数据为例)进行集合排序,包括升序反序 2)根据集合的某个number数值 ...
- Java集合排序及java集合类详解
Java集合排序及java集合类详解 (Collection, List, Set, Map) 摘要内容 集合是Java里面最常用的,也是最重要的一部分.能够用好集合和理解好集合对于做Java程序的开 ...
- Scala中的集合排序
Scala中的集合排序 在scala中,排序不再像java中的那么复杂,除了Map之外,其他的集合类型都可以使用自己的排序方法,排序方法主要有三个: 1.sorted 2.sortWith 3.sor ...
- java8新特性:对map集合排序,根据key或者value操作排序(升序、降序)
java8新特性:对map集合排序,根据key或者value操作排序(升序.降序) 直接上代码: package com.drew.test; import java.util.List; impor ...
- java中集合排序的常用方法总结
前言 1.集合元素为数字 2.集合元素为对象 前言 平常的开发需求中肯定会遇到对集合排序问题,最常见的排序是在持久层中使用sql进行排序,但是由于业务限制或是其他原因,不能在持久层 ...
最新文章
- 【ACM】杭电OJ 4704 Sum (隔板原理+组合数求和公式+费马小定理+快速幂)
- 8.Spring Security 权限控制
- php注释idea设置,IDEA对类生成注释以及自己定义代码生成方式
- Spring5 源码下载注意事项
- jar包中的类如何读取包内和包外的配置文件
- ES6 的发布,加速 JavaScript 框架淘汰?
- javascript 日常
- 按钮先调用页面JS,JS成功才调用后台代码
- linux定时器时间来源,linux 时间定时器 介绍
- 12 EDA技术实用教程【时序电路Verilog设计3】
- Windows:无须再忍,Microsoft Store下载慢/加速/更快,不摘抄(2022新)
- 小米蓝牙耳机使用说明_小米10手机专用?小米“真无线蓝牙耳机Air 2s”评测
- 代码自动生成-宏带来的奇计淫巧
- 精品餐饮业奢华西餐专业PPT模板
- C++横板格斗小游戏(基于Easyx图形库)
- 如何利用wordpress搭建一个免费博客
- 前端之移动web开发(下)
- 字节等单位与进制转换
- python3环境配置教程_Python3 环境搭建
- C++习题(系统菜单设计)
热门文章
- 30岁,我从前端转型管理成功了
- 华硕主板破linux密码破解,华硕P8B75-M-LE老主板加持NVMe SSD bios(刷新软件和bios)...
- 网友发给我一个游戏钓鱼网站,我用python渗透了该网站所有信息!
- 调整姿势!登顶 MacBook高效工作环境配置!
- 鲲鹏开发者技术峰会·福州圆满落幕!
- 基于Java的连连看游戏设计与实现(含源文件)
- DeepFaceLab
- 微软更新补丁手动下载地址
- 数控车计算机软件编程的重要性,数控车床有多少人软件编程?
- Android 12 WiFi 框架