【Java8新特性系列】 Comparator interface接口原理示例源码分析

Java8 Comparator interface接口原理示例源码分析

由来

Java 8中的Comparator接口引入了一些新特性和方法来提供更灵活和方便的比较操作。以下是Java 8中Comparator接口的新特性和方法总结:

  1. 默认方法(Default Methods):Java 8在接口中引入了默认方法,这些方法可以在接口中直接实现,默认方法为接口提供了一种向后兼容的方式。Comparator接口中定义了几个默认方法,例如thenComparingInt()thenComparingLong()thenComparingDouble()等。

  2. 静态方法(Static Methods):Java 8还引入了接口中的静态方法,这些方法可以直接通过接口名称调用,而无需实现接口的类或对象。Comparator接口中定义了几个静态方法,例如reverseOrder()naturalOrder()nullsFirst()nullsLast()等。

  3. Lambda表达式支持:由于Comparator是一个函数式接口,Java 8引入了Lambda表达式的支持,使得可以更简洁地创建和使用比较器。

  4. 方法引用支持:同样由于Comparator是一个函数式接口,Java 8还引入了方法引用的支持,可以使用方法引用来创建比较器的实例。

  5. 新增的排序方法:Comparator接口新增了一些排序方法,例如comparing()comparingInt()comparingLong()comparingDouble()等,这些方法接受一个函数作为参数,用于从对象中提取排序键,然后根据提取的键进行比较。

  6. 复合排序:Java 8引入了复合排序的方法,例如thenComparing()reversed()thenComparing()方法可以在现有比较器的基础上进行进一步的排序,而reversed()方法可以返回当前比较器的逆序比较器。

总的来说,Java 8中的Comparator接口通过引入默认方法、静态方法以及新增的排序方法,提供了更加灵活和便捷的比较操作。同时,Lambda表达式和方法引用的支持使得使用Comparator接口更加简洁和易读。这些改进使得在Java中进行对象排序变得更加高效和方便。

示例

Java 8 中的 Comparator 接口是一个函数式接口,用于定义对象之间的顺序比较规则。它提供了多个方法来实现自定义比较逻辑。下面是每种方法的总结、代码示例和输出结果。

1. compare(T o1, T o2)
这是 Comparator 接口的核心方法,用于比较两个对象的顺序。如果第一个对象小于第二个对象,则返回负整数;如果两个对象相等,则返回零;如果第一个对象大于第二个对象,则返回正整数。

Comparator<Integer> comparator = (o1, o2) -> o1 - o2;
int result = comparator.compare(5, 10);
System.out.println(result); // 输出 -5

2. reversed()
返回当前 Comparator 的逆序版本。即,如果原始 Comparator 的 compare 方法返回负整数,则逆序版本返回正整数;如果原始 Comparator 的 compare 方法返回正整数,则逆序版本返回负整数。

Comparator<Integer> comparator = (o1, o2) -> o1 - o2;
Comparator<Integer> reversedComparator = comparator.reversed();
int result = reversedComparator.compare(5, 10);
System.out.println(result); // 输出 5

3. thenComparing(Comparator<? super T> other)
将当前 Comparator 与另一个 Comparator 进行级联比较。首先使用当前 Comparator 进行比较,如果比较结果为零,则使用另一个 Comparator 进行比较。

Comparator<String> lengthComparator = Comparator.comparingInt(String::length);
Comparator<String> alphabeticalComparator = Comparator.naturalOrder();

Comparator<String> finalComparator = lengthComparator.thenComparing(alphabeticalComparator);

int result1 = finalComparator.compare("apple", "banana");
int result2 = finalComparator.compare("banana", "apple");

System.out.println(result1); // 输出 -1,因为"apple"长度小于"banana"
System.out.println(result2); // 输出 1,因为"banana"长度大于"apple"

4. nullsFirst(Comparator<? super T> comparator)
返回一个比较器,将 null 值视为最小值,并使用指定的比较器进行比较。

Comparator<Integer> comparator = Comparator.nullsFirst(Integer::compareTo);
Integer value1 = null;
Integer value2 = 10;

int result = comparator.compare(value1, value2);
System.out.println(result); // 输出 -1,因为 null 小于 10

5. nullsLast(Comparator<? super T> comparator)
返回一个比较器,将 null 值视为最大值,并使用指定的比较器进行比较。

Comparator<Integer> comparator = Comparator.nullsLast(Integer::compareTo);
Integer value1 = null;
Integer value2 = 10;

int result = comparator.compare(value1, value2);
System.out.println(result); // 输出 1,因为 null 大于 10

是的,还有其他一些方法可以用于定制化对象之间的比较规则。

6. comparing(Function<? super T, ? extends U> keyExtractor)
根据指定的键提取函数对对象进行比较。该方法接受一个 Function 参数,用于从对象中提取一个键(某个属性或字段),然后根据这个键进行比较。

List<String> names = Arrays.asList("John", "Jane", "Alex", "Mike");

Comparator<String> comparator = Comparator.comparing(String::length);
names.sort(comparator);

System.out.println(names); // 输出 [Alex, John, Jane, Mike]

7. comparingInt(ToIntFunction<? super T> keyExtractor)
类似于 comparing() 方法,但是针对整型键值进行比较。

List<Integer> numbers = Arrays.asList(10, 5, 8, 3);

Comparator<Integer> comparator = Comparator.comparingInt(number -> number);
numbers.sort(comparator);

System.out.println(numbers); // 输出 [3, 5, 8, 10]

8. comparingLong(ToLongFunction<? super T> keyExtractor)
类似于 comparing() 方法,但是针对长整型键值进行比较。

9. comparingDouble(ToDoubleFunction<? super T> keyExtractor)
类似于 comparing() 方法,但是针对双精度浮点型键值进行比较。

是的,还有其他一些方法可以用于定制化对象之间的比较规则。

10. thenComparing(Function<? super T, ? extends U> keyExtractor)
在当前比较器的基础上,根据指定的键提取函数对对象进行进一步比较。与 thenComparing(Comparator<? super T> other) 不同,该方法使用键提取函数而不是另一个比较器。

List<String> names = Arrays.asList("John", "Jane", "Alex", "Mike");

Comparator<String> comparator = Comparator.comparing(String::length)
    .thenComparing(String::compareToIgnoreCase);

names.sort(comparator);

System.out.println(names); // 输出 [Alex, Jane, John, Mike]

11. reversed()
返回当前比较器的逆序版本。它会改变对象的排序顺序。

List<Integer> numbers = Arrays.asList(5, 2, 8, 1);

Comparator<Integer> comparator = Comparator.naturalOrder();
numbers.sort(comparator.reversed());

System.out.println(numbers); // 输出 [8, 5, 2, 1]

12. naturalOrder()
返回一个按照自然顺序(升序)进行比较的比较器。比较的对象必须实现 Comparable 接口。

List<String> names = Arrays.asList("John", "Jane", "Alex", "Mike");

Comparator<String> comparator = Comparator.naturalOrder();
names.sort(comparator);

System.out.println(names); // 输出 [Alex, Jane, John, Mike]

13. nullsFirst() 和 nullsLast()
这两个方法与之前提到的 nullsFirst(Comparator<? super T> comparator)nullsLast(Comparator<? super T> comparator) 方法功能相同,但是它们是静态方法,直接通过 Comparator 类调用。

中文源码

/**
 * 比较函数,对某个对象集合施加<i>全序</i>。可以将比较器传递给排序方法(例如{@link Collections#sort(List,Comparator) Collections.sort}
 * 或 {@link Arrays#sort(Object[],Comparator) Arrays.sort}),以允许对排序顺序进行精确控制。
 * 比较器也可以用于控制某些数据结构的顺序(如{@link SortedSet sorted sets}或{@link SortedMap sorted maps}),
 * 或者为没有{@link Comparable 自然顺序}的对象集合提供排序。<p>
 *
 * 比较器<c> c </c>对元素集合<c> S </c>施加的排序被称为与等价关系一致,当且仅当<c>c.compare(e1, e2)==0</c>的布尔值和<c>e1.equals(e2)</c>
 * 对于<c>S</c>中的每一个<tt>e1</tt>和<tt>e2</tt>都具有相同的布尔值时。 <p>
 *
 * 当使用能够与equals不一致的比较器来对排序集(或排序映射)进行排序时,应该小心。
 * 假设使用具有显式比较器<c>c</c>的排序集(或排序映射)与从集合<c>S</c>中取出的元素(或键)一起使用。
 * 如果<c>c</c>对<c>S</c>上的排序与equals不一致,则排序集(或排序映射)将表现“奇怪”。
 * 特别地,排序集(或排序映射)将违反集合(或映射)的一般契约,该契约是根据equals定义的。<p>
 *
 * 例如,假设添加了两个元素{@code a}和{@code b},使得{@code (a.equals(b) && c.compare(a, b) != 0)}到一个空的{@code TreeSet}与比较器{@code c}。
 * 第二个{@code add}操作将返回true(并且树集的大小将增加),因为从树集的角度来看,{@code a}和{@code b}在视觉上不等,
 * 即使这与{@link Set#add Set.add}方法的规范相反。<p>
 *
 * 注意:对于比较器来说,通常最好也实现<tt>java.io.Serializable</tt>,因为它们可能被用作可序列化数据结构(如{@link TreeSet}、{@link TreeMap})中的排序方法。
 * 为了使数据结构能够成功序列化,如果提供了比较器,则比较器(如果提供)必须实现<tt>Serializable</tt>。<p>
 *
 * 对于数学倾向者,给定比较器<c> c </c>对给定对象集合<c> S </c>施加的<i>强制排序</i>的<i>关系</i>是:<pre>
 *       {(x, y) such that c.compare(x, y) &lt;= 0}.
 * </pre> 此总序的<i>商</i>为:<pre>
 *       {(x, y) such that c.compare(x, y) == 0}.
 * </pre>
 *
 * 根据<tt>compare</tt>的合同,商是<c> S </c>上的一个等价关系,并且强加的排序是<c> S </c>上的一个全序。
 * 当我们说<c>c</c>对<c>S</c>施加的排序与equals一致时,我们指的是排序的商是对象的{@link Object#equals(Object) equals(Object)}方法定义的等价关系:<pre>
 *     {(x, y) such that x.equals(y)}. </pre>
 *
 * <p>与{@code Comparable}不同,比较器可以可选地允许空参数的比较,同时保持等价关系的要求。
 *
 * <p>该接口是Java集合框架的成员。
 *
 * @param <T> 可以由此比较器进行比较的对象类型
 *
 * @see Comparable
 * @see java.io.Serializable
 * @since 1.2
 */
@FunctionalInterface
public interface Comparator<T> {
    /**
     * 对两个参数进行排序。根据第一个参数是否小于、等于还是大于第二个参数,
     * 返回一个负整数、零或正整数。<p>
     *
     * 在前面的描述中,符号<tt>sgn(</tt><i>expression</i><tt>)</tt>指定了数学的<i>signum</i>函数,
     * 根据表达式的值是否为负、零或正,返回<tt>-1</tt>、<tt>0</tt>或<tt>1</tt>之一。<p>
     *
     * 实现者必须确保对于所有的x和y,<tt>sgn(compare(x, y)) == -sgn(compare(y, x))</tt>。
     * (这意味着如果且仅当<tt>compare(y, x)</tt>抛出异常时,<tt>compare(x, y)</tt>也会抛出异常。)<p>
     *
     * 实现者还必须确保关系是传递的:<tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt>意味着<tt>compare(x, z)&gt;0</tt>。<p>
     *
     * 最后,实现者必须确保<tt>compare(x, y)==0</tt>意味着<tt>sgn(compare(x, z))==sgn(compare(y, z))</tt>对于所有的<tt>z</tt>。<p>
     *
     * 通常情况下,任何违反此条件的比较器应明确指出此事实。推荐的语言是“注意:此比较器强加了与equals不一致的排序。”
     *
     * @param o1 要进行比较的第一个对象。
     * @param o2 要进行比较的第二个对象。
     * @return 一个负整数、零或正整数,根据第一个参数是小于、等于还是大于第二个参数。
     * @throws NullPointerException 如果参数为null并且此比较器不允许空参数
     * @throws ClassCastException 如果参数的类型阻止它们通过此比较器进行比较。
     */
    int compare(T o1, T o2);

    /**
     * 指示某个对象是否“等于”此比较器。该方法必须遵守{@link Object#equals(Object)}的一般契约。
     * 此外,仅当指定的对象也是一个比较器并且它施加与此比较器相同的排序时,该方法才能返回true。
     * 因此,<code>comp1.equals(comp2)</code>意味着对于每个对象引用<tt>o1</tt>和<tt>o2</tt>,<tt>sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2))</tt>。<p>
     *
     * 注意,除非重写了<tt>Object.equals(Object)</tt>,否则总是安全的不重写这个方法。
     * 但是,在某些情况下,重写此方法可能会提高性能,因为它允许程序确定两个不同的比较器是否施加相同的顺序。
     *
     * @param   obj   用于比较的参考对象。
     * @return  <code>true</code>仅当指定的对象也是比较器并且它施加与此比较器相同的排序时。
     * @see Object#equals(Object)
     * @see Object#hashCode()
     */
    boolean equals(Object obj);

    /**
     * 返回一个比该比较器的逆序排列的比较器。
     *
     * @return 比该比较器的逆序排列的比较器。
     * @since 1.8
     */
    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

    /**
     * 返回一个词典顺序比较器与另一个比较器。
     * 如果这个{@code Comparator}认为两个元素相等,即{@code compare(a, b) == 0},
     * {@code other}用来确定顺序。
     *
     * <p>如果指定的比较器也是可序列化的,则返回的比较器也是可序列化的。
     *
     * @apiNote
     * 例如,要根据长度和不区分大小写的自然排序对字符串集合进行排序,可以使用以下代码组合比较器:
     *
     * <pre>{@code
     *     Comparator<String> cmp = Comparator.comparingInt(String::length)
     *             .thenComparing(String.CASE_INSENSITIVE_ORDER);
     * }</pre>
     *
     * @param  other 在这个比较器比较两个对象相等时使用的另一个比较器。
     * @return 由此比较器和其他比较器组成的词典顺序比较器。
     * @throws NullPointerException 如果参数为null。
     * @since 1.8
     */
    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);
        };
    }

    /**
     * 返回一个具有提取键以与给定{@code Comparator}进行比较的函数的词典顺序比较器。
     *
     * @implSpec 默认实现行为就像{@code thenComparing(comparing(keyExtractor, cmp))}一样。
     *
     * @param  <U>  排序键的类型
     * @param  keyExtractor 用于提取排序键的函数
     * @param  keyComparator 用于比较排序键的{@code Comparator}
     * @return 由此比较器和提取的键的比较组成的词典顺序比较器
     * @throws NullPointerException 如果任一参数为null。
     * @see #comparing(Function, Comparator)
     * @see #thenComparing(Comparator)
     * @since 1.8
     */
    default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }

    /**
     * 返回一个具有提取{@code Comparable}排序键的函数的词典顺序比较器。
     *
     * @implSpec 默认实现行为就像{@code thenComparing(comparing(keyExtractor))}一样。
     *
     * @param  <U>  {@link Comparable}排序键的类型
     * @param  keyExtractor 用于提取{@link Comparable}排序键的函数
     * @return 由此比较器和然后是{@link Comparable}排序键组成的词典顺序比较器。
     * @throws NullPointerException 如果参数为null。
     * @see #comparing(Function)
     * @see #thenComparing(Comparator)
     * @since 1.8
     */
    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        return thenComparing(comparing(keyExtractor));
    }
}

/**
 * 返回一个按字典顺序比较器,其中包含提取整数排序键的函数。
 *
 * @implSpec 此默认实现行为类似于 {@code thenComparing(comparingInt(keyExtractor))}。
 *
 * @param  keyExtractor 用于提取整数排序键的函数
 * @return 由当前比较器和整数排序键组成的按字典顺序比较器
 * @throws NullPointerException 如果参数为null。
 * @see #comparingInt(ToIntFunction)
 * @see #thenComparing(Comparator)
 * @since 1.8
 */
default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
    return thenComparing(comparingInt(keyExtractor));
}

/**
 * 返回一个按字典顺序比较器,其中包含提取长整型排序键的函数。
 *
 * @implSpec 此默认实现行为类似于 {@code thenComparing(comparingLong(keyExtractor))}。
 *
 * @param  keyExtractor 用于提取长整型排序键的函数
 * @return 由当前比较器和长整型排序键组成的按字典顺序比较器
 * @throws NullPointerException 如果参数为null。
 * @see #comparingLong(ToLongFunction)
 * @see #thenComparing(Comparator)
 * @since 1.8
 */
default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
    return thenComparing(comparingLong(keyExtractor));
}

/**
 * 返回一个按字典顺序比较器,其中包含提取双精度浮点数排序键的函数。
 *
 * @implSpec 此默认实现行为类似于 {@code thenComparing(comparingDouble(keyExtractor))}。
 *
 * @param  keyExtractor 用于提取双精度浮点数排序键的函数
 * @return 由当前比较器和双精度浮点数排序键组成的按字典顺序比较器
 * @throws NullPointerException 如果参数为null。
 * @see #comparingDouble(ToDoubleFunction)
 * @see #thenComparing(Comparator)
 * @since 1.8
 */
default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
    return thenComparing(comparingDouble(keyExtractor));
}

/**
 * 返回一个按照<em>自然顺序</em>的逆序排列的比较器。
 *
 * <p>返回的比较器可序列化,并在比较{@code null}时抛出{@link NullPointerException}。
 *
 * @param  <T> 要比较的元素的{@link Comparable}类型
 * @return 一个比较器,它对{@code Comparable}对象施加<em>自然顺序</em>的逆序。
 * @see Comparable
 * @since 1.8
 */
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
    return Collections.reverseOrder();
}

/**
 * 返回一个按照自然顺序比较{@link Comparable}对象的比较器。
 *
 * <p>返回的比较器可序列化,并在比较{@code null}时抛出{@link NullPointerException}。
 *
 * @param  <T> 要比较的元素的{@link Comparable}类型
 * @return 一个比较器,它对{@code Comparable}对象施加<em>自然顺序</em>。
 * @see Comparable
 * @since 1.8
 */
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
    return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
}

/**
 * 返回一个空值友好的比较器,将{@code null}视为小于非{@code null}值。当两者都是{@code null}时,它们被视为相等。
 * 如果两者都不是{@code null},则使用指定的{@code Comparator}来确定顺序。如果指定的比较器为{@code null},
 * 则返回的比较器将认为所有非{@code null}值相等。
 *
 * <p>如果指定的比较器可序列化,则返回的比较器也可序列化。
 *
 * @param  <T> 要比较的元素的类型
 * @param  comparator 用于比较非{@code null}值的{@code Comparator}
 * @return 一个比较器,它将{@code null}视为小于非{@code null}值,并使用提供的{@code Comparator}来比较非{@code null}对象。
 * @since 1.8
 */
public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
    return new Comparators.NullComparator<>(true, comparator);
}

/**
 * 返回一个空值友好的比较器,将{@code null}视为大于非{@code null}值。当两者都是{@code null}时,它们被视为相等。
 * 如果两者都不是{@code null},则使用指定的{@code Comparator}来确定顺序。如果指定的比较器为{@code null},
 * 则返回的比较器将认为所有非{@code null}值相等。
 *
 * <p>如果指定的比较器可序列化,则返回的比较器也可序列化。
 *
 * @param  <T> 要比较的元素的类型
 * @param  comparator 用于比较非{@code null}值的{@code Comparator}
 * @return 一个比较器,它将{@code null}视为大于非{@code null}值,并使用提供的{@code Comparator}来比较非{@code null}对象。
 * @since 1.8
 */
public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
    return new Comparators.NullComparator<>(false, comparator);
}

/**
 * 接受从类型{@code T}中提取排序键的函数,并返回一个使用指定的{@link Comparator}按该排序键进行比较的{@code Comparator<T>}。
 *
 * <p>如果指定的函数和比较器都可序列化,则返回的比较器也可序列化。
 *
 * @apiNote
 * 例如,要获取一个按姓氏比较{@code Person}对象的{@code Comparator},忽略大小写差异:
 *
 * <pre>{@code
 *     Comparator<Person> cmp = Comparator.comparing(
 *             Person::getLastName,
 *             String.CASE_INSENSITIVE_ORDER);
 * }</pre>
 *
 * @param  <T> 要比较的元素的类型
 * @param  <U> 排序键的类型
 * @param  keyExtractor 用于提取排序键的函数
 * @param  keyComparator 用于比较排序键的{@code Comparator}
 * @return 一个按提取的键使用指定的{@code Comparator}进行比较的比较器
 * @throws NullPointerException 如果任一参数为null
 * @since 1.8
 */
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));
}

/**
 * 接受从类型{@code T}中提取{@link java.lang.Comparable Comparable}排序键的函数,并返回一个按该排序键进行比较的{@code Comparator<T>}。
 *
 * <p>如果指定的函数可序列化,则返回的比较器也可序列化。
 *
 * @apiNote
 * 例如,要获取一个按姓氏比较{@code Person}对象的{@code Comparator}:
 *
 * <pre>{@code
 *     Comparator<Person> byLastName = Comparator.comparing(Person::getLastName);
 * }</pre>
 *
 * @param  <T> 要比较的元素的类型
 * @param  <U> {@code Comparable}排序键的类型
 * @param  keyExtractor 用于提取{@link Comparable}排序键的函数
 * @return 一个按提取的键进行比较的比较器
 * @throws NullPointerException 如果参数为null
 * @since 1.8
 */
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));
}

/**
 * 接受从类型{@code T}中提取整数排序键的函数,并返回一个按该排序键进行比较的{@code Comparator<T>}。
 *
 * <p>如果指定的函数可序列化,则返回的比较器也可序列化。
 *
 * @param  <T> 要比较的元素的类型
 * @param  keyExtractor 用于提取整数排序键的函数
 * @return 一个按提取的键进行比较的比较器
 * @see #comparing(Function)
 * @throws NullPointerException 如果参数为null
 * @since 1.8
 */
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
}

/**
 * 接受从类型{@code T}中提取长整型排序键的函数,并返回一个按该排序键进行比较的{@code Comparator<T>}。
 *
 * <p>如果指定的函数可序列化,则返回的比较器也可序列化。
 *
 * @param  <T> 要比较的元素的类型
 * @param  keyExtractor 用于提取长整型排序键的函数
 * @return 一个按提取的键进行比较的比较器
 * @see #comparing(Function)
 * @throws NullPointerException 如果参数为null
 * @since 1.8
 */
public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
}

/**
 * 接受从类型{@code T}中提取双精度浮点数排序键的函数,并返回一个按该排序键进行比较的{@code Comparator<T>}。
 *
 * <p>如果指定的函数可序列化,则返回的比较器也可序列化。
 *
 * @param  <T> 要比较的元素的类型
 * @param  keyExtractor 用于提取双精度浮点数排序键的函数
 * @return 一个按提取的键进行比较的比较器
 * @see #comparing(Function)
 * @throws NullPointerException 如果参数为null
 * @since 1.8
 */
public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值