Guava记录 - Ordering (二) - Chainin
Ordering - Chaining解析
一、简介
官网对Ordering - Chaining简介如下:
A given Ordering can be wrapped to obtain derived orderings
大致意思为是可以对给定的排序进行包装,以获得派生的排序.并列出了以下可能会使用到的部分方法:
image.png好了,废话不多说,直接进入实验.
二、Ordering的Chaining试验
实验列表如下:
step1 测试Chaining-reverse()
Ordering使用reverse()方法将会得到一个当前Ordering取反排序的Ordering.
简单源码解析:
/**
* Returns the reverse of this ordering; the {@code Ordering} equivalent to {@link
* Collections#reverseOrder(Comparator)}.
*
* <p><b>Java 8 users:</b> Use {@code thisComparator.reversed()} instead.
*/
// type parameter <S> lets us avoid the extra <String> in statements like:
// Ordering<String> o = Ordering.<String>natural().reverse();
@GwtCompatible(serializable = true)
public <S extends T> Ordering<S> reverse() {
return new ReverseOrdering<S>(this);
}
此处会发现调用reverse()方法后,将返回一个名为ReverseOrdering的Ordering.
ReverseOrdering(Ordering<? super T> forwardOrder) {
this.forwardOrder = checkNotNull(forwardOrder);
}
@Override
public int compare(T a, T b) {
return forwardOrder.compare(b, a);
}
而最终不难发现ReverseOrdering基于当前的Ordering,重写了compare()方法,做了取反比较.
简单实验代码:
//==========================================ordering - Chaining实验===============================
System.out.println("===========================测试ordering - chaining试验======================");
//测试自定义ordering排序器
//自定义数字大小排序器 - 根据数字由小到大排序
Ordering<Integer> byNumerOrdering = new Ordering<Integer>() {
@Override
public int compare(Integer left, Integer right) {
return Ints.compare(left, right);
}
};
System.out.println("===========================测试Chaining-reverse()试验======================");
List<Integer> testChainingReverseList = Lists.newArrayList(1, 6, 3, 4, 2, 5);
System.out.println("正常通过自定义ordering排序器输出:" + JsonMoreUtils.toJson(byNumerOrdering.sortedCopy(testChainingReverseList)));
System.out.println("chaining-reverse排序器输出:" + JsonMoreUtils.toJson(byNumerOrdering.reverse().sortedCopy(testChainingReverseList)));
System.out.println("chaining-reverse排序器重复使用输出:" + JsonMoreUtils.toJson(byNumerOrdering.reverse().reverse().sortedCopy(testChainingReverseList)));
实验结果:
===========================测试ordering - chaining试验======================
===========================测试Chaining-reverse()试验======================
正常通过自定义ordering排序器输出:[1,2,3,4,5,6]
chaining-reverse排序器输出:[6,5,4,3,2,1]
chaining-reverse排序器重复使用输出:[1,2,3,4,5,6]
值得注意的是使用reverse()方法的时候,输入的比较对象中不要含有NULL,否则会出现NPE.
step2 测试Chaining-nullsFirst()
Guava还提供了支持NULL比较的Ordering.
使用nullsFirst()方法将会返回一个在非空元素之前为空排序的排序,否则其行为与原始排序相同的Ordering.
与nullsLast()类似.
简单源码解析:
/**
* Returns an ordering that treats {@code null} as less than all other values and uses {@code
* this} to compare non-null values.
*
* <p><b>Java 8 users:</b> Use {@code Comparator.nullsFirst(thisComparator)} instead.
*/
// type parameter <S> lets us avoid the extra <String> in statements like:
// Ordering<String> o = Ordering.<String>natural().nullsFirst();
@GwtCompatible(serializable = true)
public <S extends T> Ordering<S> nullsFirst() {
return new NullsFirstOrdering<S>(this);
}
此处会发现调用nullsFirst()方法后,将返回一个名为NullsFirstOrdering的Ordering.
NullsFirstOrdering(Ordering<? super T> ordering) {
this.ordering = ordering;
}
@Override
public int compare(@Nullable T left, @Nullable T right) {
if (left == right) {
return 0;
}
if (left == null) {
return RIGHT_IS_GREATER;
}
if (right == null) {
return LEFT_IS_GREATER;
}
return ordering.compare(left, right);
}
最终发现NullsFirstOrdering基于当前的Ordering,重写了compare()方法,做了null比较,非null为大.同时为null,right为大.
简单实验代码:
List<Integer> testChainingReverseList = Lists.newArrayList(1, 6, 3, 4, 2, 5,null);
System.out.println("===========================测试Chaining-nullsFirst()试验======================");
System.out.println("Chaining-nullsFirst()排序器输出:" + byNumerOrdering.nullsFirst().sortedCopy(testChainingReverseList));
实验结果:
===========================测试Chaining-nullsFirst()试验======================
Chaining-nullsFirst()排序器输出:[null, 1, 2, 3, 4, 5, 6]
step3 测试Chaining-nullsLast()
使用nullsLast()方法将会返回一个在非空元素之后为空排序的排序,否则其行为与原始排序相同的Ordering.
与nullsFirst()类似.
简单源码解析:
/**
* Returns an ordering that treats {@code null} as greater than all other values and uses this
* ordering to compare non-null values.
*
* <p><b>Java 8 users:</b> Use {@code Comparator.nullsLast(thisComparator)} instead.
*/
// type parameter <S> lets us avoid the extra <String> in statements like:
// Ordering<String> o = Ordering.<String>natural().nullsLast();
@GwtCompatible(serializable = true)
public <S extends T> Ordering<S> nullsLast() {
return new NullsLastOrdering<S>(this);
}
此处会发现调用nullsFirst()方法后,将返回一个名为NullsLastOrdering的Ordering.
NullsLastOrdering(Ordering<? super T> ordering) {
this.ordering = ordering;
}
@Override
public int compare(@Nullable T left, @Nullable T right) {
if (left == right) {
return 0;
}
if (left == null) {
return LEFT_IS_GREATER;
}
if (right == null) {
return RIGHT_IS_GREATER;
}
return ordering.compare(left, right);
}
最终发现NullsLastOrdering基于当前的Ordering,重写了compare()方法,做了null比较,非null为小.同时为null,left为大.
简单实验代码:
List<Integer> testChainingReverseList = Lists.newArrayList(1, 6, 3, 4, 2, 5,null);
System.out.println("===========================测试Chaining-nullsLast()试验======================");
System.out.println("Chaining-nullsLast()排序器输出:" + byNumerOrdering.nullsLast().sortedCopy(testChainingReverseList));
实验结果:
===========================测试Chaining-nullsLast()试验======================
Chaining-nullsLast()排序器输出:[1, 2, 3, 4, 5, 6, null]
step4 测试Chaining-compound()
使用compound()方法将会返回一个复合排序.
简单源码解析:
/**
* Returns an ordering which first uses the ordering {@code this}, but which in the event of a
* "tie", then delegates to {@code secondaryComparator}. For example, to sort a bug list first by
* status and second by priority, you might use {@code byStatus.compound(byPriority)}. For a
* compound ordering with three or more components, simply chain multiple calls to this method.
*
* <p>An ordering produced by this method, or a chain of calls to this method, is equivalent to
* one created using {@link Ordering#compound(Iterable)} on the same component comparators.
*
* <p><b>Java 8 users:</b> Use {@code thisComparator.thenComparing(secondaryComparator)} instead.
* Depending on what {@code secondaryComparator} is, one of the other overloads of {@code
* thenComparing} may be even more useful.
*/
@GwtCompatible(serializable = true)
public <U extends T> Ordering<U> compound(Comparator<? super U> secondaryComparator) {
return new CompoundOrdering<U>(this, checkNotNull(secondaryComparator));
}
此处会发现调用compound()方法后,将返回一个名为CompoundOrdering的Ordering.
CompoundOrdering(Comparator<? super T> primary, Comparator<? super T> secondary) {
this.comparators = ImmutableList.<Comparator<? super T>>of(primary, secondary);
}
CompoundOrdering(Iterable<? extends Comparator<? super T>> comparators) {
this.comparators = ImmutableList.copyOf(comparators);
}
@Override
public int compare(T left, T right) {
// Avoid using the Iterator to avoid generating garbage (issue 979).
int size = comparators.size();
for (int i = 0; i < size; i++) {
int result = comparators.get(i).compare(left, right);
if (result != 0) {
return result;
}
}
return 0;
}
最终发现CompoundOrdering基于当前的Ordering,重写了compare()方法,如果存在多个比较器,将根据顺序执行,如果没有比较出大小,将比较过程下沉到下一个顺位的比较器中.
也就是说当我们原有的ordering比较出大小相同时,将使用compound中的比较器比较结果作为本次比较的结果.
简单实验代码:
List<Integer> testChainingCompoundList = Lists.newArrayList(1, 6, 3, 4, 2, 5, 11);
System.out.println("===========================测试Chaining-compound()试验======================");
Ordering<Integer> byNumbersLengthOrdering = new Ordering<Integer>() {
@Override
public int compare(Integer left, Integer right) {
return Ints.compare(String.valueOf(right).length(), String.valueOf(left).length());
}
};
System.out.println("Chaining-compound()排序器使用前根据数字长度大小输出:" + byNumbersLengthOrdering.sortedCopy(testChainingCompoundList));
System.out.println("Chaining-compound()排序器使用后 数字长度 -> 数字大小 输出:" + byNumbersLengthOrdering.compound(byNumerOrdering).sortedCopy(testChainingCompoundList));
//注意:也就是说当我们原有的ordering比较出大小相同时,将使用compound中的比较器比较作为结果.
实验结果:
===========================测试Chaining-compound()试验======================
Chaining-compound()排序器输出:[11, 1, 6, 3, 4, 2, 5]
Chaining-compound()排序器输出:[11, 1, 2, 3, 4, 5, 6]
step5 测试Chaining-lexicographical()
使用lexicographical()方法将会返回一个排序,该排序根据元素按字典顺序对迭代进行排序.
简单源码解析:
/**
* Returns a new ordering which sorts iterables by comparing corresponding elements pairwise until
* a nonzero result is found; imposes "dictionary order". If the end of one iterable is reached,
* but not the other, the shorter iterable is considered to be less than the longer one. For
* example, a lexicographical natural ordering over integers considers {@code [] < [1] < [1, 1] <
* [1, 2] < [2]}.
*
* <p>Note that {@code ordering.lexicographical().reverse()} is not equivalent to {@code
* ordering.reverse().lexicographical()} (consider how each would order {@code [1]} and {@code [1,
* 1]}).
*
* <p><b>Java 8 users:</b> Use {@link Comparators#lexicographical(Comparator)} instead.
*
* @since 2.0
*/
@GwtCompatible(serializable = true)
// type parameter <S> lets us avoid the extra <String> in statements like:
// Ordering<Iterable<String>> o =
// Ordering.<String>natural().lexicographical();
public <S extends T> Ordering<Iterable<S>> lexicographical() {
/*
* Note that technically the returned ordering should be capable of
* handling not just {@code Iterable<S>} instances, but also any {@code
* Iterable<? extends S>}. However, the need for this comes up so rarely
* that it doesn't justify making everyone else deal with the very ugly
* wildcard.
*/
return new LexicographicalOrdering<S>(this);
}
此处会发现调用lexicographical()方法后,将返回一个名为LexicographicalOrdering的Ordering.
final Comparator<? super T> elementOrder;
LexicographicalOrdering(Comparator<? super T> elementOrder) {
this.elementOrder = elementOrder;
}
@Override
public int compare(Iterable<T> leftIterable, Iterable<T> rightIterable) {
Iterator<T> left = leftIterable.iterator();
Iterator<T> right = rightIterable.iterator();
while (left.hasNext()) {
if (!right.hasNext()) {
return LEFT_IS_GREATER; // because it's longer
}
int result = elementOrder.compare(left.next(), right.next());
if (result != 0) {
return result;
}
}
if (right.hasNext()) {
return RIGHT_IS_GREATER; // because it's longer
}
return 0;
}
最终发现LexicographicalOrdering基于当前的Ordering,重写了compare()方法
简单实验代码:
System.out.println("===========================测试Chaining-lexicographical()试验======================");
List<Integer> testChaininglexicographicalList1 = Lists.newArrayList(1, 6, 3, 4, 2, 11, 5);
List<Integer> testChaininglexicographicalList2 = Lists.newArrayList(1, 6, 3, 4, 2);
List<Integer> testChaininglexicographicalList3 = Lists.newArrayList(1, 6, 3, 4, 1);
List<Integer> testChaininglexicographicalList4 = Lists.newArrayList(1, 6, 3, 4, 3);
List<List<Integer>> testList = new ArrayList<>();
testList.add(testChaininglexicographicalList2);
testList.add(testChaininglexicographicalList1);
testList.add(testChaininglexicographicalList3);
testList.add(testChaininglexicographicalList4);
System.out.println("Chaining-lexicographical()排序器输出:" + JsonMoreUtils.toJson(byNumerOrdering.lexicographical().sortedCopy(testList)));
实验结果:
===========================测试Chaining-lexicographical()试验======================
Chaining-lexicographical()排序器输出:[[1,6,3,4,1],[1,6,3,4,2],[1,6,3,4,2,11,5],[1,6,3,4,3]]
step6 测试Chaining-onResultOf()
使用onResultOf()方法将会返回一个排序,返回一个排序,该排序通过将函数应用于值,然后使用原始排序比较结果。
简单源码解析:
/**
* Returns a new ordering on {@code F} which orders elements by first applying a function to them,
* then comparing those results using {@code this}. For example, to compare objects by their
* string forms, in a case-insensitive manner, use:
*
* <pre>{@code
* Ordering.from(String.CASE_INSENSITIVE_ORDER)
* .onResultOf(Functions.toStringFunction())
* }</pre>
*
* <p><b>Java 8 users:</b> Use {@code Comparator.comparing(function, thisComparator)} instead (you
* can omit the comparator if it is the natural order).
*/
@GwtCompatible(serializable = true)
public <F> Ordering<F> onResultOf(Function<F, ? extends T> function) {
return new ByFunctionOrdering<F, T>(function, this);
}
此处会发现调用onResultOf()方法后,将返回一个名为ByFunctionOrdering的Ordering.
final Function<F, ? extends T> function;
final Ordering<T> ordering;
ByFunctionOrdering(Function<F, ? extends T> function, Ordering<T> ordering) {
this.function = checkNotNull(function);
this.ordering = checkNotNull(ordering);
}
@Override
public int compare(F left, F right) {
return ordering.compare(function.apply(left), function.apply(right));
}
最终发现ByFunctionOrdering基于当前的Ordering,重写了compare()方法,
比较的是应用过函数的值.
简单实验代码:
System.out.println("===========================测试Chaining-onResultOf()试验======================");
List<Integer> testChainingonResultOfList = Lists.newArrayList(1, 6, 3, 4, 2, 5, 11);
System.out.println("Chaining-onResultOf()排序器输出:" + JsonMoreUtils.toJson(byNumerOrdering.onResultOf(data -> {
assert data != null;
return data.hashCode();
}).sortedCopy(testChainingonResultOfList)));
实验结果:
===========================测试Chaining-onResultOf()试验======================
Chaining-onResultOf()排序器输出:[1,2,3,4,5,6,11]
未完待续................