9

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
assylias
  • 321,522
  • 82
  • 660
  • 783
  • I get the expected `java.lang.IllegalStateException: stream has already been operated upon or closed` with java 1.8.0_60 – Alexis C. Nov 03 '15 at 19:32
  • @AlexisC. Weird (at least your output makes more sense than mine) - I'm on 1.8.0_60 too - Windows x64. – assylias Nov 03 '15 at 19:34
  • What happens if you comment out the first line (with the min) so the stream is open? – Yosef Weiner Nov 03 '15 at 19:37
  • @SkinnyJ Same thing - I still get the exception – assylias Nov 03 '15 at 19:38
  • Indeed that's weird, I'm on OS X 10.11.1 if that helps. – Alexis C. Nov 03 '15 at 19:42
  • I'm getting the same behavior as @AlexisC. 1.8.0_60 Windows x64 – Yosef Weiner Nov 03 '15 at 19:46
  • 1
    Hmm, JDK 1.8.0_60 Windows 10 x64, I get the same behaviour as the OP, i.e. `LambdaConversionException` is thrown... I do have `IllegalStateException` if I change `max` argument to `(t1, t2) -> t1.compareTo(t2)` instead of `T::compareTo`. – Tunaki Nov 03 '15 at 19:47
  • Looks like I get the `LambdaConversionException` with ECJ. Are you sure you're not using that? – Yosef Weiner Nov 03 '15 at 20:00
  • 1
    [This](http://stackoverflow.com/questions/27031244/lambdaconversionexception-with-generics-jvm-bug) looks similar but I can reproduce that one even with javac 1.8.0_60, which I cannot do with the example in this case. – Yosef Weiner Nov 03 '15 at 20:28
  • @assylias what if you make `T` only extend `Comparable` (not `Number`) – Yosef Weiner Nov 03 '15 at 20:34
  • 2
    Of course, you could just use `Comparator.naturalOrder()` instead of `T::compareTo` but it’s a pity that there are still problems with multiple bounds… – Holger Nov 03 '15 at 20:38
  • 1
    @SkinnyJ: I can still reproduce the problem of that question with `jdk1.8.0_60` – Holger Nov 03 '15 at 20:48
  • @Holger I must have been unclear. Agree, I can reproduce the problem of that question with 1.8.0_60; but I can't reproduce THIS question's problem with that compiler (although I can with ECJ). To me indicates that the issues are slightly different. – Yosef Weiner Nov 03 '15 at 20:51
  • 1
    @SkinnyJ: I see. Well, there's at least [something](https://bugs.openjdk.java.net/browse/JDK-8058112) which has been fixed in `u45`. – Holger Nov 03 '15 at 20:57
  • 2
    Keep in mind that the compiler is involved. When using an older compiler, like the one integrated into Netbeans, you get the problem, even if the runtime is uptodate. – Holger Nov 03 '15 at 21:01
  • @SkinnyJ removing Number solves the problem but there seems to be a bug anyway... – assylias Nov 03 '15 at 21:55
  • Apparently it is a bug – Sleiman Jneidi Nov 03 '15 at 22:04
  • 1
    I get the `LambdaConversionException` with Eclipse Luna SR2 (4.4.2) compiler, but works fine with JDK 1.8.0_51 compiler (Windows). Are you using Eclipse? Which version. Smells like a bug. – clstrfsck Nov 03 '15 at 22:22
  • @assylias right but it points to the multiple bonds issue (or something similar). Can you confirm if you are compiling with eclipse or javac? – Yosef Weiner Nov 04 '15 at 07:03
  • 1
    @SkinnyJ It seems to be a Netbeans problem - when running the same from the command line I get the expected output but when running from Netbeans (which uses javac) I get the output in my question. – assylias Nov 04 '15 at 07:26

4 Answers4

6

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

Sleiman Jneidi
  • 22,907
  • 14
  • 56
  • 77
4

The call site initialization problem is addressed through JDK-8058112 available in JDK 8u40 b17 or later.

Yosef Weiner
  • 5,432
  • 1
  • 24
  • 37
Srikanth
  • 41
  • 1
3

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.

hahn
  • 3,588
  • 20
  • 31
2

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.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • I don't think it is Netbeans fault, check my answer, it was reported as a bug in the complier – Sleiman Jneidi Nov 04 '15 at 11:14
  • @SleimanJneidi I don't think that's the case. That bug was fixed in 8u40 and I have the problem with 8u60 + the code compiles and runs fine with javac (but not in Netbeans). – assylias Nov 04 '15 at 11:27
  • 1
    If you turn off "compile on save", the problem disappears. Perhaps that turns off the Netbeans compiler and switches to javac? – Yosef Weiner Nov 04 '15 at 16:30