美文网首页
Guava记录 - Ordering (二) - Chainin

Guava记录 - Ordering (二) - Chainin

作者: 一点温柔 | 来源:发表于2019-10-14 00:05 被阅读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]
    

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

    相关文章

      网友评论

          本文标题:Guava记录 - Ordering (二) - Chainin

          本文链接:https://www.haomeiwen.com/subject/rtwkmctx.html