2

I am trying to create a class implementing comparable. When all the class elements are integer, everything works well. When I go with String and use comparing rather than comparingInt, I receive the following errors.

  • Incorrect number of type arguments for generic method comparing(Function) of type Comparator; it cannot be parameterized with arguments

  • The type myClassdoes not define getFrom(T) that is applicable here

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);
    }
}

Could someone point out what I might be missing here?

2
  • 3
    remove the generic type and it should work or explicitly Comparator.<myClass, String>comparing... Commented Jul 29, 2019 at 17:01
  • @michalk when I explicitly wrote it, it worked. Could you please explain me why this happens? Commented Jul 29, 2019 at 17:04

2 Answers 2

3

Comparator::comparing is a generic method that takes a function that is used to extract the value to be compared. You passed a method reference to myClass::getFrom method which returns a String and will be invoked on myClass type object (through Function::apply). That is why you have to pass generic types myClass and String.

However you could ommit those generic types because you are assigning your comparator to Comparator<myClass> comp variable so types can be inferred automatically (also using types from your method reference used).

Looking further let's look at Comparator::comparing(Function) method implementation :

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));
    }));
}

Here T will be myClass and U will be String. Function var0 will take myClass as parameter and will return String (so method reference to myClass::getFrom will work here - generally it will be like invoking getFrom on myClass object). Actually as you can see this method will return a Comparator as a lambda function which will use function var0 to extract values from var1x and var2x (both of them will be myClass types). For me it looks a bit like a closure.

Sign up to request clarification or add additional context in comments.

Comments

2

Okay, a few things here. First of all, here's working code which mostly just removes the type arguments you provided.

You can do this because they will be automatically inferred. You only have to do it explicitly when they aren't inferrable (which your IDE will tell you). There is plenty of info on type inference scattered around the Java docs; e.g. 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);
    }
}

Some other notes that are helpful in general or for SO for future reference:

  • Upper case first letter in class name.
  • Try to strip down your code to a full/reproducible example. For example, this uses 2 fields both of which exist and can be pasted into an IDE. The question one uses 4 fields most of which aren't present.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.