I am playing with the new Java 8 features: lambdas, default and static methods in interfaces.
This code works fine:
@FunctionalInterface
interface Comparator<T> {
    int compare(T a, T b);
    static <T> Comparator<T> comparing(Function<T, Comparable> f) {
        return (a, b) -> f.apply(a).compareTo(f.apply(b));
    }
    default Comparator<T> thenComparing(Comparator<T> comp) {
        return (a, b) -> compare(a, b) == 0 ? comp.compare(a, b) : compare(a, b);
    }
    default Comparator<T> thenComparing(Function<T, Comparable> f) {
        return thenComparing(comparing(f));
    }
}
Hower if I inline thenComparing(Comparator<T> comp) into thenComparing(Function<T, Comparable> f):
@FunctionalInterface
interface Comparator<T> {
    int compare(T a, T b);
    static <T> Comparator<T> comparing(Function<T, Comparable> f) {
        return (a, b) -> f.apply(a).compareTo(f.apply(b));
    }
    default Comparator<T> thenComparing(Function<T, Comparable> f) {
        return (a, b) -> compare(a, b) == 0 ? comparing(f) : compare(a, b);
    }
}
the compilation fails with:
error: incompatible types: bad return type in lambda expression
  return (a, b) -> compare(a, b) == 0 ? comparing(f) : compare(a, b);
                                                       ^
bad type in conditional expression
  no instance(s) of type variable(s) T exist so that Comparator<T> conforms to int
where T is a type-variable:
  T extends Object declared in method <T>comparing(Function<T,Comparable>)
Why?
Another version without using Comparable as a raw-type:
@FunctionalInterface
interface Comparator<T> {
    int compare(T a, T b);
    static <T, U extends Comparable<U>> Comparator<T> comparing(Function<T, U> f) {
        return (a, b) -> f.apply(a).compareTo(f.apply(b));
    }
    default Comparator<T> thenComparing(Comparator<T> comp) {
        return (a, b) -> compare(a, b) == 0 ? comp.compare(a, b) : compare(a, b);
    }
    default <V extends Comparable<V>> Comparator<T> thenComparing(Function<T, V> f) {
        return thenComparing(comparing(f));
    }
}
                This can't work because:
comparing(f) returns a Comparator<T>
compare(a, b) returns an int
So the types are not compatible in the ternary expression:
(a, b) -> compare(a, b) == 0 ? comparing(f) : compare(a, b);
                               ^----------^   ^-----------^
                               Comparator<T>       int
What you want is to call .compare(a, b) on the next to compare comparator, if the first one returned equal items:
default Comparator<T> thenComparing(Function<T, Comparable> f) {
    return (a, b) -> compare(a, b) == 0 ? comparing(f).compare(a, b) : compare(a, b);
}
As a side-note, you are using Comparable as a raw-type. Don't do that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With