目录
排序器Ordering,是Guava流畅风格比较器[Comparator]的实现,它可以用来为构建复杂的比较器,以完成集合排序的功能。
1. 排序器的创建
Ordering静态创建排序器
方法 | 描述 |
natural() | 对可排序类型做自然排序,如数字按大小,日期按先后排序 |
usingToString() | 按对象的字符串形式做字典排序[lexicographical ordering] |
from(Comparator) | 把给定的Comparator转化为排序器 |
以natural方法为例
2. 剖析与原生排序的区别
以natural方法为例,剖析dubbo提供的集合工具类和guava排序器的区别
list.sort(Ordering.natural()); //源码分析
// list.sort(Ordering.natural())
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
// Arrays.sort(a, (Comparator) c);
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
CollectionUtils.sort(list); //源码分析
// CollectionUtils.sort(list)
public static <T> List<T> sort(List<T> list) {
if (isNotEmpty(list)) {
Collections.sort(list);
}
return list;
}
// Collections.sort(list)
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
可见,CollectionUtils.sort只是包了一层,底层也是调用了list.sort方法,只是比较器为null
再往下看,可看到排序时的比较核心代码,guava的方式是使用自己实现Comparator的compare方法去比较,而dubbo提供的集合工具类则是通过类本身实现的compareTo方法去比较
// list.sort(Ordering.natural())
c.compare(a[runHi], a[runHi - 1]) < 0
// CollectionUtils.sort(list)
(Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0
Integer类实现的compareTo方法如下
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
guava的Ordering排序起实现了Comparator,实现了compare方法,但实际上在本例子Integer类型的排序中,NaturalOrdering的比较方法最终用的还是Integer类的compareTo方法
@Override
public abstract int compare(@Nullable T left, @Nullable T right);
// NaturalOrdering
@Override
public int compare(Comparable left, Comparable right) {
checkNotNull(left); // for GWT
checkNotNull(right);
return left.compareTo(right);
}
每种排序器实现的compare方法不同
3. 链式调用
通过链式调用,可以由给定的排序器衍生出其它排序器
3.1 reverse()
获取语义相反的排序器
list.sort(Ordering.natural().reverse()); // 9,7,4,3,1
3.2 nullsFirst()/nullsLast()
使用当前排序器,并将null值放在最前面/最后面。若排序列表中有null值,用原生排序会报空指针异常
List<Integer> list = Lists.newArrayList(1, 3, 9, null, 4, 7);
list.sort(Ordering.natural().nullsFirst()); // list:[null,1,3,4,7,9]
list.sort(Ordering.natural().nullsLast()); // list:[1,3,4,7,9,null]
当阅读链式调用产生的排序器时,应该从后往前读。之所以要从后往前读,是因为每次链式调用都是用后面的方法包装了前面的排序器。例如上面,是先将null值放在列表最前面,再去自然排序。
4 运用排序器
Guava的排序器实现有若干操纵集合或元素值的方法
4.1 isOrdered
判断可迭代对象是否已按排序器排序:允许有排序值相等的元素。
List<Integer> list = Lists.newArrayList(1, 3, 9, 4, 7);
boolean result = Ordering.natural().isOrdered(list); // false
4.2 greatestOf
获取可迭代对象中前的k个元素。
List<Integer> list2 = Ordering.natural().greatestOf(list, 3);
// list2:[9,7,4]
List<Integer> list3 = Ordering.natural().reverse().greatestOf(list, 3);
// list3:[1,3,4]
4.3 min/max
获取最大最小值
Integer max = Ordering.natural().max(list);// 9
Integer min = Ordering.natural().min(list);// 1