Guava记录 - Ordering (二) - Chainin

2019-10-14  本文已影响0人  一点温柔

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]

未完待续................

上一篇下一篇

猜你喜欢

热点阅读