Generics compiles and runs in Eclipse, but doesn't compile in javac
Asked Answered
B

3

23

Note: This is a spin-off from Comparable and Comparator contract with regards to null

This code compiles and runs fine in Eclipse (20090920-1017)

import java.util.*;
public class SortNull {
   static <T extends Comparable<? super T>>
   Comparator<T> nullComparableComparator() {
      return new Comparator<T>() {
         @Override public int compare(T el1, T el2) {
         return
            el1 == null ? -1 :
            el2 == null ? +1 :
            el1.compareTo(el2);
         }
      };
   }
   public static void main(String[] args) {
      List<Integer> numbers = new ArrayList<Integer>(
         Arrays.asList(3, 2, 1, null, null, 0)
      );
      Comparator<Integer> numbersComp = nullComparableComparator();
      Collections.sort(numbers, numbersComp);
      System.out.println(numbers);
      // "[null, null, 0, 1, 2, 3]"

      List<String> names = new ArrayList<String>(
         Arrays.asList("Bob", null, "Alice", "Carol")
      );
      Comparator<String> namesComp = nullComparableComparator();
      Collections.sort(names, namesComp);
      System.out.println(names);
      // "[null, Alice, Bob, Carol]"
   }
}

And yet it doesn't compile on javac 1.6.0_17. This is the error message:

SortNull.java:17: incompatible types; no instance(s) of type variable(s) T exist
 so that java.util.Comparator<T> conforms
 to java.util.Comparator<java.lang.Integer>
found   : <T>java.util.Comparator<T>
required: java.util.Comparator<java.lang.Integer>
     Comparator<Integer> numbersComp = nullComparableComparator();

SortNull.java:25: incompatible types; no instance(s) of type variable(s) T exist
 so that java.util.Comparator<T> conforms
 to java.util.Comparator<java.lang.String>
found   : <T>java.util.Comparator<T>
required: java.util.Comparator<java.lang.String>
     Comparator<String> namesComp = nullComparableComparator();

2 errors

Can someone explain why the discrepancy? Is this a bug? If so, who has the bug?

Boykin answered 18/5, 2010 at 15:43 Comment(0)
B
30

This is a confirmed bug: Bug ID 6468354. Here's an extract of relevance:

This problem is caused by the fact that sometimes javac's implementation of JLS3 15.12.2.8 ignores recursive bounds, sometimes not (as in this case). When recursive bounds contains wildcards, such bounds are included when computing uninferred type variables. This makes subsequent subtyping test (Integer <: Comparable<? super T> where T is a type-variable to be inferred).

Will be fixed after 6369605

Occured to me on WinXP with 1.6.0_13 as well. Ah well, I'll just stick using Eclipse :)

Baumgartner answered 18/5, 2010 at 15:44 Comment(2)
No, Google is awesome.Baumgartner
LOL yes, I know how to use Google, I was just so caught up in the excitement and just post the question right away =) I hope that's not "bad question behavior" that you're encouraging by answering it =)Boykin
W
16

You can get around this by explicitly specifying the generic class:

Comparator<String> namesComp = Stack.<String>nullComparableComparator();
While answered 18/5, 2010 at 15:45 Comment(1)
Just what I was looking for!Vapory
M
0

I had a similar problem and upgraded from jdk1.6.0_16 to jdk1.6.0_23 and it went away without any code changes.

Masera answered 3/5, 2011 at 6:38 Comment(1)
I have 1.6.0_24 Java compiler, and unfortunately this issue came up. Sun's bug database specifies fix release to 7(b109) (I assume that it's JDK7), so probably you just had a luck ;) After specifying type explicitly, as Michael suggests, everything works fine.Monolith

© 2022 - 2024 — McMap. All rights reserved.