Type variables, inline method and "Bad return type in lambda expression"

I play with new Java 8 features: lambdas, standard 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));
    }
}

Lower if I am built thenComparing(Comparator<T> comp)in 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);
    }
}

fail compilation:

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 Comparableas 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));
    }
}
+4
source share
2 answers

Embedding

default Comparator<T> thenComparing(Comparator<T> comp) {
    return (a, b) -> compare(a, b) == 0 ? comp.compare(a, b) : compare(a, b);
}

at

default Comparator<T> thenComparing(Function<T, Comparable> f) {
    return thenComparing(comparing(f));
}

leads to

default Comparator<T> thenComparing(Function<T, Comparable> f) {
    return (a, b) -> compare(a, b) == 0 ? comparing(f).compare(a, b) : compare(a, b);
}

but not

default Comparator<T> thenComparing(Function<T, Comparable> f) {
    return (a, b) -> compare(a, b) == 0 ? comparing(f) : compare(a, b);
}
+4
source

This may not work because:

  • comparing(f) returns Comparator<T>
  • compare(a, b) returns int

Thus, the types are incompatible in triple expression:

(a, b) -> compare(a, b) == 0 ? comparing(f) : compare(a, b);
                               ^----------^   ^-----------^
                               Comparator<T>       int

You want to call .compare(a, b)to compare with the comparator if the first returns equal elements:

default Comparator<T> thenComparing(Function<T, Comparable> f) {
    return (a, b) -> compare(a, b) == 0 ? comparing(f).compare(a, b) : compare(a, b);
}

Comparable raw-type. .

+5

Source: https://habr.com/ru/post/1630035/


All Articles