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?

Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623

3 Answers3

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 :)

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 21
    No, [Google](http://www.google.com/search?q=%22incompatible+types%3B+no+instance%28s%29+of+type+variable%28s%29%22+site%3Abugs.sun.com) is awesome. – BalusC May 18 '10 at 15:46
  • 2
    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 =) – polygenelubricants May 18 '10 at 15:48
16

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

Comparator<String> namesComp = Stack.<String>nullComparableComparator();
Michael
  • 34,873
  • 17
  • 75
  • 109
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.

WW.
  • 23,793
  • 13
  • 94
  • 121
  • 2
    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. – omnomnom May 31 '12 at 11:00