Java-List集合排序之Comparable与Comparator的使用
* 在使用Collection的sort排序的集合元素都必须是Comparable接口的实现类,该接口表示子类是可以比较的。
* 同时实现接口必须重写抽象方法。
* - int compareTo(T t);
* 该方法用于使当前对象与给定对象进行比较。
* 返回值为一个int值,该值表示大小关系,它不关注具体的取值是多少,而关注的是取值范围。
* 当返回值>0时:当前对象比参数对象大(T是传入的参数,this表示当前对象)
* 当返回值<0时:当前对象比参数对象小(T是传入的参数,this表示当前对象)
* 当返回值=0时:当前对象等于参数对象(T是传入的参数,this表示当前对象)
package example.demo03;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author yuanchaoyong
*/
public class ComparatorTest {
public static void main(String[] args) {
// 测试案例1
testInteger();
// 测试案例2
testString();
}
/**
* List<Integer> 排序测试
* Integer 默认实现了Comparable接口
* Collections.sort默认是升序排序(自然排序)
*/
public static void testInteger(){
List<Integer> integers = Arrays.asList(12,7,15,4);
Collections.sort(integers);
System.out.println(integers);
}
/**
* List<String> 排序测试
* String 默认实现了Comparable接口
* Collections.sort默认是升序排序(自然排序)
*/
public static void testString(){
List<String> strings = Arrays.asList("aaa","ccc","bbb","rrr");
Collections.sort(strings);
System.out.println(strings);
}
}
输出结果
package example.demo03;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author yuanchaoyong
*/
public class ComparatorTest02 {
public static void main(String[] args) {
List<User> users = Arrays.asList(new User("王五",50),new User("张三",30),new User("李四",40));
Collections.sort(users);
System.out.println(users);
}
}
/**
* 用户对象
* name
* age
*/
class User implements Comparable<User>{
String name;
Integer age;
User(String n, Integer a) {
name = n;
age = a;
}
@Override
public int compareTo(User u) {
return this.age - u.age ;
}
@Override
public String toString() {
return String.format("{name=%s, age=%d}", name, age);
}
}
通过以上案例知道,Comparable的确实现了我们想要的排序结果。但是使用Collections的sort(List<T> list)
方法排序集合时,集合元素必须实现Comparable接口并且定义比较规则。这个时候就开始出现一些问题。比如我们同一个工程使用了User对象,单个场景使用age进行排序,但是另一种情况下使用name排序,这个时候就出现了冲突。并且集合元素需要去实现Comparable接口,这对于我们的代码会有一些"侵入性",也不利于我们后续的代码扩展。
所以一般不建议使用,推荐使用Collections的sort(List<T> list, Comparator<? super T> c)的重载方法。
Collections的sort(List<T> list, Comparator<? super T> c)
* 重载的sort方法要求传入一个外部的比较器。
* 该方法不再要求集合元素必须实现Comparable接口。
* 并且也不再使用集合元素自身的比较规则排序了,而是根据给定的这个额外的比较器的比较规则,对集合元素进行排序。
* 实际开发中也推荐使用这种方式排序集合元素,若集合元素是自定义的,创建比较器时也推荐使用匿名内部类的形式。
package example.demo03;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author yuanchaoyong
*/
public class ComparatorTest03 {
public static void main(String[] args) {
List<Student> students = Arrays.asList(new Student("张三",30),new Student("李四",40),new Student("王五",50));
// 使用匿名内部类进行排序
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 自定义排序规则
return o1.age- o2.age;
}
});
System.out.println(students);
}
}
class Student {
String name;
Integer age;
Student(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return String.format("{name=%s, age=%d}", name, age);
}
}
结果
package example.demo03;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author yuanchaoyong
*/
public class ComparatorTest03 {
public static void main(String[] args) {
//test01();
test02();
}
/**
* 使用List自带的排序方法
*/
private static void test02() {
List<Student> students = Arrays.asList(new Student("张三",30),new Student("李四",40),new Student("王五",50));
students.sort(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.age- o2.age;
}
});
System.out.println(students);
}
/**
* Collections.sort方法测试
*/
private static void test01() {
List<Student> students = Arrays.asList(new Student("张三",30),new Student("李四",40),new Student("王五",50));
// 使用匿名内部类进行排序
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 自定义排序规则
return o1.age- o2.age;
}
});
System.out.println(students);
}
}
class Student {
String name;
Integer age;
Student(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return String.format("{name=%s, age=%d}", name, age);
}
}
JDK8之lambda简化写法
Comparator接口是一个函数式接口,所以我们可以使用更优秀的写法,简化代码。
函数式接口就是只定义一个抽象方法的接口。
JDK1.8开始支持默认方法,即便这个接口拥有很多默认方法,只要接口只有一个抽象方法,那么这个接口就是函数式接口。
package example.demo03;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author yuanchaoyong
*/
public class ComparatorTest04 {
public static void main(String[] args) {
test02();
}
/**
* lambda写法测试
*/
private static void test02() {
List<Teacher> teachers = Arrays.asList(new Teacher("张三", 30), new Teacher("李四", 40), new Teacher("王五", 50));
// 多种写法,以下只是作为参考
// 写法1
// teachers.stream().sorted((o1,o2)-> o1.age- o2.age).collect(Collectors.toList());
// 写法2
//Collections.sort(teachers,(o1,o2)-> o1.getAge()- o2.getAge());
// 写法3
List<Teacher> teacherList = teachers.stream().
sorted((Comparator.comparingInt(Teacher::getAge)))
.collect(Collectors.toList());
System.out.println(teachers);
}
}
class Teacher {
String name;
Integer age;
Teacher(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
@Override
public String toString() {
return String.format("{name=%s, age=%d}", name, age);
}
}
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()));//先以属性一升序,再进行属性二降序
//空/Null数据排序
list.stream().sorted(Comparator.comparing(类::属性一).thenComparing(item -> item.属性二, Comparator.nullsLast(Date::compareTo))).collect(Collectors.toList());
//空/Null数据分组
Map<String, List<类>> map = list.stream().collect(Collectors.groupingBy(item -> {
if (item.属性一 == null || item.属性一.equals("")) {
return "";
}
return DateFormat.getDateInstance().format(item.属性一);
}))
人要耐得住寂寞,才能守得住繁华。人生最痛苦的就是拿不起放不下,不属于自己的快乐,及时放手也许是一种解脱,生活中没有谁对谁错,只有适不适合。当发现很多已经改变,更要面对的是事实。