Comparator Comparators Comparable Collections排序源码解析
问题引出
起初,写了一行排序代码,空指针异常。有判空思想但对nullsLast理解是错误的,于是阅读了一下相关源码。
result.sort(Comparator.nullsLast(Comparator.comparing(StationPointDataZoneVO::getDv)));
以下写法是正确的:
result.sort(Comparator.comparing(StationPointDataZoneVO::getDv, Comparator.nullsFirst(Comparator.comparing(Function.identity()))).reversed());
接下来,以Comparator 接口为引,探究一下比较器各个方法的正确用法。
Comparator.comparing
有两个核心方法
public static <T, U> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor,
Comparator<? super U> keyComparator)
{
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (Comparator<T> & Serializable)
(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
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));
}
先说下面一个,传入一个取值函数,一般情况是以某字段为依据给对象排序,如 StationPointDataZoneVO::getDv。比较自身 Function.identity() 即可。返回一个Comparator接口的具体实现,需要注意的是,比较器最终调用的方法是实现了Comparable接口的某个对象的compareTo方法。
第一个方法传入两个参数,一个取值函数,一个比较器。最终调用比较器的compare方法。
以下写法效果一样,同样使用某对象自己实现的compareTo方法。
result.sort(Comparator.comparing(StationPointDataZoneVO::getDv));
result.sort(Comparator.comparing(StationPointDataZoneVO::getDv, Comparator.comparing(Function.identity())));
result.sort(Comparator.comparing(StationPointDataZoneVO::getDv, Comparator.naturalOrder()));
Comparator.thenComparing
thenComparing有好几个方法,本质都调用的这个。
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);
};
}
不难看懂,就是上一个比较器结果相等时,调用下一个比较器,可以嵌套很多层。
Comparator.naturalOrder nullsFirst nullsLast
这三个有一个共同特点,返回 Comparators类中的某个比较器实例。
NaturalOrderComparator
enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
INSTANCE;
@Override
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c1.compareTo(c2);
}
@Override
public Comparator<Comparable<Object>> reversed() {
return Comparator.reverseOrder();
}
}
NullComparator
构造器和核心方法
NullComparator(boolean nullFirst, Comparator<? super T> real) {
this.nullFirst = nullFirst;
this.real = (Comparator<T>) real;
}
@Override
public int compare(T a, T b) {
if (a == null) {
return (b == null) ? 0 : (nullFirst ? -1 : 1);
} else if (b == null) {
return nullFirst ? 1: -1;
} else {
return (real == null) ? 0 : real.compare(a, b);
}
}
回到开篇的问题,为何会报空指针就不难理解,
进入到NullComparator的compare后,a和b其实是StationPointDataZoneVO对象,它确实不为null。于是调用传入的比较器的compare方法,最终调用到的是
(StationPointDataZoneVO::getDv).compareTo(StationPointDataZoneVO::getDv).
dv取值为null,于是空指针。
Comparator.reversed reverseOrder
此时牵扯进来了,另一个类,Collections。
reversed 和reverseOrder分别返回Collections定义的ReverseComparator2比较器和ReverseComparator比较器。
这两个比较器的区别是,前者用传入的比较器做翻转比较,(即compare方法参数翻转)
public int compare(T t1, T t2) {
return cmp.compare(t2, t1);
}
后者直接翻转调用compareTo
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
Comparators
此类用于支持Comparator接口,提供两个比较器NaturalOrderComparator,NullComparator
Collections
也提供了两个比较器ReverseComparator,ReverseComparator2