Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Lambda to comparator conversion - intermediate representation

I'm trying to make sense of how Comparator.comparing function works. I created my own comparing method to understand it.

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
    BiFunction<T,T,Integer> bfun = (T a, T b) -> f.apply(a).compareTo(f.apply(b));
    return (Comparator<T>) bfun;
}

The last line in this function throws an exception.

However, if I change this function to

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
    return (T a, T b) -> f.apply(a).compareTo(f.apply(b));
}

It works just fine as expected.

What is the intermediate functional interface which the second attempt uses, which is able to convert the lambda to Comparator?

like image 652
patentfox Avatar asked Nov 03 '17 16:11

patentfox


2 Answers

What is the intermediate functional interface which the second attempt uses, which is able to convert the lambda to Comparator?

The Comparator itself.

Within the second method, you have defined a Comparator, not an intermediate object that has been cast to the Comparator.

The last line in this function throws an exception.

Yes, it should.

If two classes are functional interfaces and have similar methods (with the identical signatures and the same return type), it doesn't mean that they can be used interchangeably.


An interesting trick - you may make a Comparator<T> by referring to the BiFunction<T, T, Integer> bfun's method apply:

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
    final BiFunction<T,T,Integer> bfun = (T a, T b) -> f.apply(a).compareTo(f.apply(b));
    return bfun::apply; // (a, b) -> bfun.apply(a, b);
}
like image 62
Andrew Tobilko Avatar answered Nov 16 '22 06:11

Andrew Tobilko


The intermediate functional interface in your second attempt is simply Comparator<T>:

You can see this because your code-snippet is equivalent to the following:

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) {
    Comparator<T> comparator = (T a, T b) -> f.apply(a).compareTo(f.apply(b));
    return comparator;
}
like image 6
Thomas Fritsch Avatar answered Nov 16 '22 06:11

Thomas Fritsch