在 Comparator 中使用 String 时出错

Having an error when using String in Comparator

我正在尝试创建一个 class 可比较的实现。当所有 class 元素都是整数时,一切正常。当我使用 String 并使用 comparing 而不是 comparingInt 时,我收到以下错误。

public class myClass implements Comparable<myClass> {
    @Column (name="From")
    private String from;
    @Column (name="To")
    private String to;
    @Column (name="With")
    private String with;
    @Column (name="amount")
    private int amount;

    // Setters, getters, constructor

    Comparator<myClass > comp = Comparator.<myClass>comparing(myClass::getFrom)
            .thenComparing(myClass::getTo)
            .thenComparing(myClass::getWith)
            .thenComparingInt(myClass::getAmount);
    @Override
    public int compareTo(myClass o) {
        return comp.compare(this, o);
    }
}

有人可以指出我在这里可能遗漏了什么吗?

好的,这里有几件事。首先,这是工作代码,主要只是删除了您提供的类型参数。

您可以这样做,因为系统会自动推断出它们。你只需要在它们不可推断时明确地做(你的 IDE 会告诉你)。 Java 文档中散布着大量关于类型推断的信息;例如https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html

import java.util.Comparator;

public class MyClass implements Comparable<MyClass>{
    private String from;
    private String to;

    public String getFrom() { return from; }
    public String getTo() { return to; }

    Comparator<MyClass> comp = Comparator.comparing(MyClass::getFrom)
            .thenComparing(MyClass::getTo);

    @Override
    public int compareTo(MyClass o) {
        return comp.compare(this, o);
    }
}

其他一些对一般情况或 SO 有帮助以供将来参考的注释:

  • class 名称中的首字母大写。
  • 尝试将您的代码简化为 full/reproducible 示例。例如,这使用 2 个字段,它们都存在并且可以粘贴到 IDE 中。第一个问题使用了 4 个字段,其中大部分不存在。

Comparator::comparing 是一种通用方法,它采用用于提取要比较的值的函数。您将方法引用传递给 myClass::getFrom 方法,该方法 return 是 String 并将在 myClass 类型对象上调用(通过 Function::apply)。这就是为什么你必须传递泛型类型 myClassString.

但是您可以忽略这些泛型类型,因为您将比较器分配给 Comparator<myClass> comp 变量,因此可以自动推断类型(也可以使用所用方法引用中的类型)。

让我们进一步看一下 Comparator::comparing(Function) 方法实现:

static <T, U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T, ? extends U> var0) {
    Objects.requireNonNull(var0);
    return (Comparator)((Serializable)((var1x, var2x) -> {
        return ((Comparable)var0.apply(var1x)).compareTo(var0.apply(var2x));
    }));
}

此处 T 将是 myClassU 将是 String。函数 var0 将采用 myClass 作为参数并将 return String (因此对 myClass::getFrom 的方法引用将在这里起作用 - 通常它就像调用 getFrommyClass 对象上)。实际上,如您所见,此方法将 return 一个 Comparator 作为 lambda 函数,它将使用函数 var0var1xvar2x 中提取值(两者它们将是 myClass 类型)。对我来说,它看起来有点像闭包。