Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8244503

Type inference fails with generic method references

XMLWordPrintable

    • x86_64
    • linux

      ADDITIONAL SYSTEM INFORMATION :
      javac 15-ea build 21

      A DESCRIPTION OF THE PROBLEM :
      When a method accepting a functional interfarce gets a generic method reference, the type inference may not work correctly.

      In the following example, the first examples do not compile, producing "error: no suitable method found for thenComparing(Comparator<T#1>)". Please note, that using a non-generic method reference, as explicitly specifying the type, works.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile the attached snippet.


      ---------- BEGIN SOURCE ----------
      import java.util.Map;
      import java.util.Comparator;


      public class Foo {

          private static final Map<String, Integer> FREQUENCES = Map.of("a", 2, "b", 3);

          public static void test() {
              // Failing:
              // 1a: When chained
              Comparator<String> c1 = Comparator.comparingInt(FREQUENCES::get)
                      .thenComparing(Comparator.naturalOrder()); // <- 'error: no suitable method found for thenComparing(Comparator<T#1>)'
              // 1b: With LVTI
              var compByFreqAsc = Comparator.comparingInt(FREQUENCES::get);
              Comparator<String> c2 = compByFreqAsc.thenComparing(Comparator.naturalOrder()); // <- 'error: no suitable method found for thenComparing(Comparator<T#1>)'

              // Compiling:
              // 2a: With non-generic method reference
              Comparator<String> c5 = Comparator.comparingInt(Foo::frequency)
                      .thenComparing(Comparator.naturalOrder());
              // 2b: With lambda parameter type declaration
              Comparator<String> c3 = Comparator.comparingInt((String s) -> FREQUENCES.get(s))
                      .thenComparing(Comparator.naturalOrder());
              // 2c: With generic method explicit type parameter declaration
              Comparator<String> c4 = Comparator.<String>comparingInt(FREQUENCES::get)
                      .thenComparing(Comparator.naturalOrder());
              // 2d: With intermediate variable
              Comparator<String> compByFreqAsc2 = Comparator.comparingInt(FREQUENCES::get);
              Comparator<String> c6 = compByFreqAsc2.thenComparing(Comparator.naturalOrder());
          }

          private static int frequency(String s) {
              return FREQUENCES.get(s);
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The workarounds (also shown in the code):
      - Use non-generic method reference, if possible (2a)
      - Replace with a lambda, *and* specify the parameter type (2b)
      - Specify the generic method type (2c)
      - Use an intermediate variable with explicit type declaration (2d)

      FREQUENCY : always


            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: