The code below compiles fine but throws an exception at runtime. Is this the expected behaviour and why?
Code:
public static void main(String[] args) {
A<Integer> a = new A<> ();
System.out.println(a.min()); //prints null as expected
System.out.println(a.max()); //throws exception
}
static class A<T extends Number & Comparable<? super T>> {
Stream<T> s = Stream.empty();
public T min() { return s.min((t1, t2) -> t1.compareTo(t2)).orElse(null); }
public T max() { return s.max(T::compareTo).orElse(null); }
}
Output:
null
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
at abc$A.max(abc.java:19)
at abc.main(abc.java:8)
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Number; not a subtype of implementation type interface java.lang.Comparable
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
... 4 more
Your code wouldn't work even if you use lambdas instead of method references because the stream is already exhausted
System.out.println(a.min());
System.out.println(a.max()); // exhausted
Streams are one off. But lets leave this apart. When you use the method reference version, it is capturing Number
as a type parameter and not Comparable
where Number
has no compareTo
maybe because Number
is more specific here.
If you just use Comparable
it will work fine
static class A<T extends Comparable<? super T>> {
Stream<T> s = Stream.empty();
public T min() { return s.min((t1, t2) -> t1.compareTo(t2)).orElse(null); }
public T max() {
T t = s.max(T::compareTo).orElse(null);
return t; }
}
System.out.println(a.max()); //null
IMO (just to be cautious) : I believe it is a bug.
What I actually believe: It is definitely a bug.
Edit: It turns out that this was actually a bug and it was fixed as confirmed by Brian Goetz. https://bugs.openjdk.java.net/browse/JDK-8058112. According to the bug database, this was fixed in 8u40
The call site initialization problem is addressed through JDK-8058112 available in JDK 8u40 b17 or later.
For those who are facing this issue in 2017 with java8 1.8.0_141
, there's another filed bug report JDK-8142476 and the fix version is java9
only.
It seems to be a Netbeans issue and I can't reproduce the problem when using javac from the command line. I have filed a bug report.
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