如何在Java 8中使用自定义比较器接口对对象数组进行排序?

4

自定义Comparator的实现

@FunctionalInterface
public interface Comparator<T>  {

int compare(T t1, T t2);

static <T> Comparator<T> comparing(
        Function<T, Comparable> f){
    return (p1, p2) -> f.apply(p1).compareTo(f.apply(p2));
}

default Comparator<T> thenComparing(
        Comparator<T> cmp){
            return (p1, p2) ->
                    this.compare(p1, p2) == 0 ?
                            cmp.compare(p1, p2) : this.compare(p1, p2);
}

default Comparator<T> thenComparing(
        Function<T, Comparable> f){
            Comparator<T> cmp = comparing(f);
    return thenComparing(cmp);
  }
}

我创建了一个Person类,拥有三个字段:firstName、lastName和age,以及它们各自的getter和setter。使用自定义的Comparator类,我想在主函数中将一个Person数组排序,如下所示:

    Comparator<Person> cmp = Comparator
            .comparing(Person::getLastName) // Extract Property and compare
            .thenComparing(Person::getFirstName)
            .thenComparing(Person::getAge);

     Person arr[] = new Person[]{
        new Person("Sean", "Gilmore", 22),
                new Person("Aaron", "Reidy", 21),
                new Person("Jane", "Kennedy", 53),
                new Person("Mike", "English", 49)
    };


    Arrays.sort(arr, cmp);

然而,Arrays.sort(arr, cmp); 抛出编译错误 no instance of type variable T exists so that Comparator<Person> conforms to Comparator<? super T>

我被这个错误搞糊涂了,我想知道如何使用 cmp 比较器按顺序排列 Person 数组。

2个回答

3

Java中的class的完全限定名称包括其包名。

Arrays.sort方法需要一个java.util.Comparator实现。您自定义的Comparatorjava.util.Comparator不同。

Arrays类中的sort方法是一个static方法,因此您无法扩展Arrays并覆盖此方法。如果要使用Arrays.sort,请使用java.util.Comparator的实现。没有其他办法。


那就意味着我必须实现排序才能使用我的自定义比较器? - harpresing
@HarpreetSingh 或者你可以为你的自定义“Comparator”类编写一个门面。不管怎样,为什么不使用真正的“Comparator”呢? - Flown
@Flown 那个 Facade 仍然是一个 java.util.Comparator - Chetan Kinger
@CKing 这就是我的意思。 - Flown
你为什么要重新发明轮子? - ncmathsadist
@ncmathsadist 只是在玩弄Java 8。 - harpresing

3

您可以很容易地将您的Comparator适配到JDK中:

Arrays.sort(arr, cmp::compare);

我相信在Java 8之前,Guava推荐了一种类似的模式来适应它们的函数式接口。


1
@shmosei cmp:compare 仍然会给你一个 java.util.Comparator。还有其他选项,但最终你只能传递一个 java.util.Comparator 到相关的方法,所以答案仍然是:你无法做到。 - Chetan Kinger
1
@CKing,我并没有将问题解释为完全避免使用JDK的“Comparator”。我认为OP只是在问他的自定义接口如何与内置的排序功能一起使用。 - shmosel
1
@shmosei 我在脑海中也被同样的论点所迷惑,但是当我读到问题中的这一行时:“我被这个错误搞糊涂了,我想知道如何使用cmp比较器对Person数组进行排序”,这使我相信OP明显需要一个解释为什么不能这样做,而不是如何做。 (OP被抛弃了,他无法将“Comparator”传递给接受“Comparator”的方法)。 这可以从OP对我的答案的评论中进一步推断出来,他说:“那么这意味着我必须实现sort才能使用我的自定义比较器吗?” OP正在探索Java! - Chetan Kinger
1
@CKing,这是我完全同意的一句话。 - shmosel
1
@etSingh cmp::compare 是一个方法引用,它转换为 (a, b) -> cmp.compare(a, b)。换句话说,你正在创建一个 JDK Comparator,该 Comparator 委托给你的自定义 Comparator,类似于 评论 中提到的 @CKing 的答案中的门面。 - shmosel
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接