大家对java接口Comparator和Comparable都不陌生,JDK8里面Comparable还和以前一样,没有什么改动;但是Comparator在之前基础上增加了很多static和default方法。本文主要结合JDK的stream编程,学习下Comparator。阅读本文需要一些前置知识,可以参考如下文章。
JDK8新特性:接口的静态方法和默认方法
http://blog.csdn.net/aitangyong/article/details/54134385
JDK8新特性:函数式接口@FunctionalInterface的使用说明
http://blog.csdn.net/aitangyong/article/details/54137067
JDK8新特性:lambda入门
http://blog.csdn.net/aitangyong/article/details/54317539
JDK8新特性:使用Method References实现方法复用,简化lambda表达式
http://blog.csdn.net/aitangyong/article/details/54586197
可以使用Stream.sort对集合进行排序,sort有2个重载方法,区别如下。
// Student实现Comparable接口,默认按照id升序排列
public class Student implements Comparable{
private int id;
private int age;
private String name;
private Address address;
public Student(int id, int age, String name, Address address) {
this.id = id;
this.age = age;
this.name = name;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Student [id=" + id + ", age=" + age + ", name=" + name + ", address=" + address + "]";
}
@Override
public int compareTo(Student o) {
return this.id - o.id;
}
}
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class TestComparator {
public static void main(String[] args) {
List students = buildStudents();
// 按照默认顺序排序
List ascList1 = students.stream().sorted().collect(Collectors.toList());
System.out.println(ascList1);
// 按照自然序排序(其实就是默认顺序)
List ascList2 = students.stream().sorted(Comparator.naturalOrder()).collect(Collectors.toList());
System.out.println(ascList2);
// 按照默认顺序的相反顺序排序
List descList = students.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
System.out.println(descList);
}
private static List buildStudents() {
List students = new ArrayList<>();
students.add(new Student(10, 20, "aty", new Address("d")));
students.add(new Student(1, 22, "qun", new Address("c")));
students.add(new Student(1, 26, "Zen", new Address("b")));
students.add(new Student(5, 23, "aty", new Address("a")));
return students;
}
}
接下来测试,都不要求Student实现Comparable接口,这里直接给出Student和Address实体类。
public class Student {
private int id;
private int age;
private String name;
private Address address;
public Student(int id, int age, String name, Address address) {
this.id = id;
this.age = age;
this.name = name;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Student [id=" + id + ", age=" + age + ", name=" + name + ", address=" + address + "]";
}
}
public class Address {
private String address;
public Address(String address) {
super();
this.address = address;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address [address=" + address + "]";
}
}
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class TestComparator {
public static void main(String[] args) {
List students = buildStudents();
// 使用lambda表达式创建Function对象
Function extractIdWay1 = (student) -> student.getId();
// 使用方法引用简化lambda
Function extractIdWay2 = Student::getId;
// Comparator.comparing(Function keyExtractor)
Comparator byId = Comparator.comparing(extractIdWay2);
// 升序
List ascList = students.stream().sorted(byId).collect(Collectors.toList());
System.out.println(ascList);
// 降序
List descList = students.stream().sorted(byId.reversed()).collect(Collectors.toList());
System.out.println(descList);
}
private static List buildStudents() {
List students = new ArrayList<>();
students.add(new Student(10, 20, "aty", new Address("d")));
students.add(new Student(1, 22, "qun", new Address("c")));
students.add(new Student(1, 26, "Zen", new Address("b")));
students.add(new Student(5, 23, "aty", new Address("a")));
return students;
}
}
如果我们想安装Address(没有实现Comparable接口)排序怎么办呢?使用另一种形式的comparing方法:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class TestComparator {
public static void main(String[] args) {
List students = buildStudents();
Comparator cmpAddr = Comparator.comparing(Address::getAddress);
Comparator byAddress = Comparator.comparing(Student::getAddress, cmpAddr);
List sortedAddressList = students.stream().sorted(byAddress).collect(Collectors.toList());
System.out.println(sortedAddressList);
}
private static List buildStudents() {
List students = new ArrayList<>();
students.add(new Student(10, 20, "aty", new Address("d")));
students.add(new Student(1, 22, "qun", new Address("c")));
students.add(new Student(1, 26, "Zen", new Address("b")));
students.add(new Student(5, 23, "aty", new Address("a")));
return students;
}
}
//getName()返回String本身已经实现了Comparable,但是我们可以自己传递一个不区分大小写的比较器
Comparator byName = Comparator.comparing(Student::getName, String.CASE_INSENSITIVE_ORDER);
List sortedNameList = students.stream().sorted(byName).collect(Collectors.toList());
System.out.println(sortedNameList);
public static void main(String[] args) {
List students = buildStudents();
Comparator byAge1 = Comparator.comparingInt(Student::getAge);
Comparator byAge2 = Comparator.comparing(Student::getAge);
List sortedAgeList1 = students.stream().sorted(byAge1).collect(Collectors.toList());
List sortedAgeList2 = students.stream().sorted(byAge2).collect(Collectors.toList());
System.out.println(sortedAgeList1);
System.out.println(sortedAgeList2);
}
private static List buildStudents() {
List students = new ArrayList<>();
students.add(new Student(10, 20, "aty", new Address("d")));
students.add(new Student(1, 22, "qun", new Address("c")));
students.add(new Student(1, 26, "Zen", new Address("b")));
students.add(new Student(5, 23, "aty", new Address("a")));
return students;
}
public class TestComparator {
public static void main(String[] args) {
List students = buildStudents();
Comparator nullNotAllowed = Comparator.comparing(Student::getId);
Comparator allowNullComparator = Comparator.nullsFirst(nullNotAllowed);
// 正常排序
List result1 = students.stream().sorted(allowNullComparator).collect(Collectors.toList());
System.out.println(result1);
// 抛异常
List result2 = students.stream().sorted(nullNotAllowed).collect(Collectors.toList());
System.out.println(result2);
}
private static List buildStudents() {
List students = new ArrayList<>();
students.add(new Student(10, 20, "aty", new Address("d")));
students.add(new Student(1, 22, "qun", new Address("c")));
students.add(new Student(1, 26, "Zen", new Address("b")));
students.add(new Student(5, 23, "aty", new Address("a")));
students.add(null);
return students;
}
}
reversed()前面已经介绍了,返回一个新的比较器(排序顺序相反)
thenComparing()系列方法与comparing()使用方法类似
如果我们先按照id排序,id相等的话再按照name排序,那么可以这样写。
public static void main(String[] args) {
List students = buildStudents();
// id升序
Comparator byIdASC = Comparator.comparing(Student::getId);
// named不分区大小写降序
Comparator byNameDESC = Comparator.comparing(Student::getName, String.CASE_INSENSITIVE_ORDER)
.reversed();
// 联合排序
Comparator finalComparator = byIdASC.thenComparing(byNameDESC);
List result = students.stream().sorted(finalComparator).collect(Collectors.toList());
System.out.println(result);
}
private static List buildStudents() {
List students = new ArrayList<>();
students.add(new Student(10, 20, "aty", new Address("d")));
students.add(new Student(1, 22, "qun", new Address("c")));
students.add(new Student(1, 26, "Zen", new Address("b")));
students.add(new Student(5, 23, "aty", new Address("a")));
return students;
}