Generics - compiler inconsistency [jdk 1.8.0_162]
The second attempt compiles correctly, because you specified the type of a variable yourself, telling the compiler what it is, because compiler does not have enough information to figure it out.
Look at this simplified example, it's from vavr
(great by the way). There is a Try<T>
class that represents a result of some operation. Generic parameter T
is the type of that result. There is a static factory to create a failure immediately, meaning we have no result here, but the generic parameter is still there:
static <T> Try<T> failure(Throwable exception) {
return new Try.Failure(exception);
}
Where does the T
come from here? The usage looks like this:
public Try<WeakHashMap> method() {
return Try.failure(new IllegalArgumentException("Some message"));
}
The Try<WeakHashMap>
here is my choice, not the compilers, you can actually put anything you want in there because you are choosing the type.
The same thing in your example, the Comparator
has generic parameter String
only, because you specified it and compiler agreed to it (like with Try<WeakHashMap>
). When you added a chained call you forced the compiler to infer the type itself, and it was Object
, because what another type it could have been?
What else you can do (notice the Testing.<String, Integer>wrap
):
public class Testing {
static interface A<F, S> {
public F getF();
public S getS();
}
static <V, S> Comparator<A<V, S>> wrap(Comparator<S> c) {
return (L, R) -> c.compare(L.getS(), R.getS());
}
public static void main(String[] args) {
Comparator<A<String, Integer>> comp = Testing.<String, Integer>wrap((L, R) -> Integer.compare(L, R))
.thenComparing(wrap((L, R) -> Integer.compare(L, R)));
}
}