目录
一、Comparable接口
想要了解它的工作原理和功能,可以打开java.lang包下的Comparable接口源码,从类和方法的注释说明中,我们可以提取到重要的信息如下:
-
Comparable接口对实现它的每个类都会赋予一种顺序,通过compareTo()方法实现自然排序;
-
自然排序的具体应用有:List列表的对象排序(Collections.sort) 、数组的对象排序(Arrays.sort)、对象作为Map的key进行排序(SortedMap,如TreeMap)、对象作为Set的元素进行排序(SortedSet,如TreeSet);
-
e1.compareTo(e2) == 0 是与 e1.equals(e2) 表达的含义一致的,特别要注意e2为null时,会抛NPE;
-
例如:e1.compareTo(e2),compareTo()方法用于比较两个对象的大小,如果返回值为0,e1等于e2;如果返回值为正整数,e1大于e2,反之,e1小于e2;
-
compareTo()方法比较两个对象时,要符合像equals()方法一样具有的自反性、对称型、传递性与一致性;
// 源码
public interface Comparable<T> {
public int compareTo(T o);
}
小结一下:
Comparable接口只有一个compareTo()方法,实现了两个对象按自然顺序(如从小到大)进行排序,应用于Collection、Array、Map等容器对象的比较排序,可看作是一种内部比较器。
二、Comparator接口
Comparator接口是为了实现更多的更复杂类型的排序而设计的,该接口利用了Java8接口方法特性,默认了许多比较方法的实现。跟随源码注释,来解读一下该接口每个方法的具体用途:
- compare():自定义比较器的排序规则(如设置o1.getAxx - o2.getAxx)。该方法比较两个对象时也具有自反性、对称型、传递性与一致性;
- equals():判断两个比较器对象是否相等;
- reversed():将元素按降序排序;
- naturalOrder():静态方法,将元素按照自然顺序排序;
- reverseOrder():静态方法,将元素按降序排序,等同于naturalOrder().reversed();
- nullsFirst():静态方法,排序的元素存在null,将null排在最前面;
- nullsLast():静态方法,排序的元素存在null,将null排在最后面;
- comparing():静态方法,定义比较器比较规则,comparingXxx()针对比较对象中元素的不同类型(comparingInt()、comparingLong()、comparingDouble()等);
- thenComparing():与comparing()搭配使用,用于先比较....再比较....的场景。
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
default Comparator<T> thenComparing(Comparator<? super T> other) {
Objects.requireNonNull(other);
return (Comparator<T> & Serializable) (c1, c2) -> {
int res = compare(c1, c2);
return (res != 0) ? res : other.compare(c1, c2);
};
}
......;
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
return Collections.reverseOrder();
}
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
}
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
return new Comparators.NullComparator<>(true, comparator);
}
public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
return new Comparators.NullComparator<>(false, comparator);
}
......;
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
......;
}
小结一下:
Comparator接口是一种外部比较器,通过自定义比较规则的形式进行排序,Java8对Comparator接口功能进行了很大的增强,常见于stream流式处理中排序的功能。
三、常见容器的排序API
Java中具有排序功能的容器数组Arrays、集合Collection(包括集合工具类Collections、其他实现类集合)、映射Map等等。
Arrays sort() API:
总的来看有下面四类排序API:(注:没有指定比较器的比较规则的,默认都是升序排序)
- sort(type []); //按升序,对数组元素排序
- sort(type [], fromIndex, toIndex); // 按升序,对数组指定范围[fromIndex,toIndex)内的元素排序
- sort(type [], Comparator c); //按照比较器对象指定的规则,对数组元素排序
- parallelSort():为并行排序,拥有上述三种类型API,这是Java8新增的API,适用于大数据量的数组排序
Collections sort() API:
看源码可知,Collections排序调用的是List接口的sort()方法,是Java8新增的API,Collections核心的排序功能仍是通过Arrays.sort(a, (Comparator) c); 实现的。
-
sort(List<T> list);//按升序,对List集合元素排序
-
sort(List<T> list, Comparator<? super T> c);//按照比较器对象指定的规则,对List集合元素排序
ArrayList/LinkedList/Vector sort() API:
看源码可知,ArrayList集合 和 Vector集合在Java8新增了排序方法,本质上都是重写了List接口的sort()方法。
- sort(Comparator<? super E> c);//按比较器对象指定的规则,对集合元素排序
TreeSet :按照默认的自然顺序,对TreeSet集合的元素进行排序。
TreeMap:按照默认的自然顺序,对TreeMap的key进行排序。
Java中实现Comparable接口的常见核心类:
-
String类;
-
包装类型;
-
BigInteger与BigDecimal等大数值类
-
枚举类等等
小结
从上述的分析来看,Comparable接口是一种自然顺序排序的接口,对未指定Comparator比较器规则的场景均默认按自然顺序排序,可理解为Comparable是一种内部比较器。而Comparator接口具有更自由的排序规则,根据不同的需求场景自定义排序,可理解为Comparator是一种外部比较器。Comparator接口在Java8进行了增强,重点放在了与stream流搭配使用时进行数据的高效处理,关于比较器的demo例子将在Java8系列整理中在写吧。不积硅步无以至千里,点滴付出终将有所收获,共同进步 ~