javajava-8ocpjp

How does method chaining work in Java 8 Comparator?


I'm prepping up for the Java 8 certificate and the following has me puzzled a littlebit, maybe someone can help me with this? In the example, a Squirrel class is modelled. It has a name and a weight. Now you can make a Comparator class to sort this thing using both fields. So first sort by name and then by weight. Something like this:

public class ChainingComparator implements Comparator<Squirrel> {
    public int compare(Squirrel s1, Squirrel s2) {

        Comparator<Squirrel> c = Comparator.comparing(s -> s.getSpecies());
        c = c.thenComparingInt(s -> s.getWeight());

        return c.compare(s1, s2);
    }
}

So far so good.. but then the puzzling part. Underneath the code example, they state that you can write this in one single line by using method chaining. Maybe I misunderstand, but when I chain the comparing and the thenComparing parts, I get a compile error. It's got to do with the types of objects that are compared (first String, then int).

Why does it work when I put in an intermediate variable and not when chaining? And is it possible to chain at all?


Solution

  • As you chain both, the compiler cannot infer the type argument of the returned comparator of comparing()because it depends on the returned comparator of thenComparingInt() that itself cannot be inferred.

    Specify the type in the lambda parameter of comparing() (or use a method reference) and it solves the inference issue as the returned type of comparing() could so be inferred. :

        Comparator<Squirrel> c = Comparator.comparing((Squirrel s)  -> s.getSpecies())
                                           .thenComparingInt(s -> s.getWeight());
    

    Note that specifying the type in the lambda parameter of thenComparingInt() (or using a method reference) such as :

        Comparator<Squirrel> c = Comparator.comparing(s -> s.getSpecies())
                                           .thenComparingInt((Squirrel s) -> s.getWeight());
    

    will not work as the receiver (here the return type of the chained method) is not considered in the inference type computation.

    This JDK 8 tutorial/documentation explains that very well :

    Note: It is important to note that the inference algorithm uses only invocation arguments, target types, and possibly an obvious expected return type to infer types. The inference algorithm does not use results from later in the program.