Issue with Comparator.comparing
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Wed Dec 12 11:19:07 UTC 2018
Hi,
this issue has been reported by Remi on amber-dev, on a discussion on
enhanced enums [1]. As suspected, I have been able to reproduce (and
simplify) the problem on a vanilla JDK - here's the test case:
import java.util.*;
import java.util.stream.*;
import java.util.function.*;
class Foo<T extends Comparable<T>> {
static Foo<String> S = new Foo<>("");
static Foo<Integer> I = new Foo<>(42);
private T t;
Foo(T t) {
this.t = t;
}
T t() {
return t;
}
public static void main(String[] args) {
List<Foo<?>> l = new ArrayList<>();
l.add(S);
l.add(I);
Comparator<? super Foo<?>> comp = Comparator.comparing(Foo::t);
//<---- ???
Collections.sort(l, comp);
}
}
This program compiles w/o warnings or errors, yet it fails at runtime
with this:
Exception in thread "main" java.lang.ClassCastException: class
java.lang.String cannot be cast to class java.lang.Integer
(java.lang.String and java.lang.Integer are in module java.base of
loader 'bootstrap')
at java.base/java.lang.Integer.compareTo(Integer.java:59)
at
java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
at
java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
at java.base/java.util.TimSort.sort(TimSort.java:220)
at java.base/java.util.Arrays.sort(Arrays.java:1516)
at java.base/java.util.ArrayList.sort(ArrayList.java:1749)
at java.base/java.util.Collections.sort(Collections.java:177)
at Foo.main(Test.java:25)
In other words, it seems like the type system is being tricked here into
thinking that the comparator is working on an homogeneous type, while in
reality there can be many types. I have a feeling that this is connected to:
https://bugs.openjdk.java.net/browse/JDK-8029307
(btw, the bug is marked as open, but the compiler dutifully applies the
capture conversion described in the spec).
If I remove the capture conversion described in that issue, the compiler
then will fail to compile the above example (as expected?):
error: incompatible types: inference variable U has incompatible bounds
Comparator<? super Foo<?>> comp = Comparator.comparing(Foo::t);
//<---- HERE
^
lower bounds: Comparable<? super U>
lower bounds: ?
where U,T are type-variables:
U extends Comparable<? super U> declared in method
<T,U>comparing(Function<? super T,? extends U>)
T extends Object declared in method <T,U>comparing(Function<? super
T,? extends U>)
1 error
To me, this looks related to this spec bug:
https://bugs.openjdk.java.net/browse/JDK-8170887
Dan, can you please confirm?
Thanks
Maurizio
[1] -
http://mail.openjdk.java.net/pipermail/amber-dev/2018-December/003816.html
More information about the compiler-dev
mailing list