一、 概述
在日常的开发工作中经常会遇到对自定义对象进行比较然后进行排序的场景,对自定义对象进行排序通常有两种实现方式:使用Comparable接口和Comparator接口。两种方式各有优劣,下面结合例子对两种实现方式做一个简单的分析。
二、Comparable接口
Comparable接口位于java.lang.Comparable,对象实现此接口并重写compareTo方法可以实现自定义的排序,这种方式使得类本身具有排序能力。Jdk文档中指出可以使用 Collection.sort() 和 Arrays.sort() 对包含实现了此接口的类的List或者数组进行排序。
下面用一个对酒店进行排序的例子进行说明:
代码示例
public class Hotel implements Cloneable, Comparable<Hotel> {
private int hotelId;
private int star;
private int score;
private int comments;
// 返回负数表示小于、正数表示大于、0表示相等, 星级越高排名越靠前,评分越高排名越靠前
@Override
public int compareTo(Hotel hotel) {
if (this.star > hotel.star) {
return -1;
} else if (this.star < hotel.star) {
return 1;
} else {
return Integer.compare(hotel.score, this.score);
}
}
public int getHotelId() {
return hotelId;
}
public void setHotelId(int hotelId) {
this.hotelId = hotelId;
}
public int getStar() {
return star;
}
public void setStar(int star) {
this.star = star;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public int getComments() {
return comments;
}
public void setComments(int comments) {
this.comments = comments;
}
public Hotel copy() {
try {
return (Hotel) this.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
@Override
public String toString() {
return "Hotel{" +
"hotelId=" + hotelId +
", star=" + star +
", score=" + score +
", comments=" + comments +
'}';
}
}
public class ComparableTest {
public static void main(String[] args) {
List<Hotel> hotelList = new ArrayList<>();
Hotel hotel = new Hotel();
hotel.setHotelId(1);
hotel.setStar(5);
hotel.setScore(4);
hotel.setComments(200);
hotelList.add(hotel);
Hotel hotel1 = hotel.copy();
hotel1.setComments(500);
hotel1.setScore(3);
hotel1.setStar(4);
hotel.setHotelId(2);
hotelList.add(hotel1);
Hotel hotel2 = hotel.copy();
hotel2.setComments(1000);
hotel2.setScore(2);
hotel2.setStar(4);
hotel2.setHotelId(3);
hotelList.add(hotel2);
System.out.println("排序前");
for (Hotel item : hotelList) {
System.out.println(item);
}
System.out.println("先按酒店星级进行排序然后按照评分排序");
Collections.sort(hotelList);
for (Hotel item : hotelList) {
System.out.println(item);
}
}
}
输出结果:
三、Comparator接口
上面的实现方式很简单,但是如果当类对象本身没有实现Comparable接口(你不能要求所有的jar包提供方自定义的类都实现Comparable接口,这不合理也不科学),那该怎么来对这些对象进行排序呢?此时就该Comparator接口大显神威了。
下面仍以对酒店进行排序的代码进行说明:
代码示例
public class ComparatorTest {
public static void main(String[] args) {
List<Hotel> hotelList = new ArrayList<>();
Hotel hotel = new Hotel();
hotel.setHotelId(1);
hotel.setStar(5);
hotel.setScore(4);
hotel.setComments(200);
hotelList.add(hotel);
Hotel hotel1 = hotel.copy();
hotel1.setComments(500);
hotel1.setScore(3);
hotel1.setStar(4);
hotel.setHotelId(2);
hotelList.add(hotel1);
Hotel hotel2 = hotel.copy();
hotel2.setComments(1000);
hotel2.setScore(2);
hotel2.setStar(4);
hotel2.setHotelId(3);
hotelList.add(hotel2);
System.out.println("排序前");
for (Hotel item : hotelList) {
System.out.println(item);
}
System.out.println("先按酒店星级进行排序然后按照评分排序");
List<Hotel> sortHotelList = hotelList.stream().sorted(getComparator()).collect(Collectors.toList());
for (Hotel item : sortHotelList) {
System.out.println(item);
}
}
private static Comparator<Hotel> getComparator() {
return new Comparator<Hotel>() {
@Override
public int compare(Hotel o1, Hotel o2) {
if (o1.getStar() > o2.getStar()) {
return -1;
} else if (o1.getStar() < o2.getStar()) {
return 1;
} else {
return Integer.compare(o2.getScore(), o1.getScore());
}
}
};
}
}
输出结果同上
使用Comparator.comparing().thenComparing实现
得益于JDK1.8新特性,还可以直接使用Comparator.comparing().thenComparing实现排序,不用再自定义比较器。
List<Hotel> sortHotelList = hotelList.stream().sorted(Comparator.comparing(Hotel::getStar)
.thenComparing(Hotel::getScore).reversed()).collect(Collectors.toList());
四、区别
- Comparable接口实现简单,需要重写CompareTo方法,可以使类本身具有排序能力
- Comparator接口可以对不具有排序能力的类实现自定义排序,需要重写compare方法
- Comparator.comparing().thenComparing 不用实现自定义比较器,简洁易用。