Java var 和 inference type ambiguity

2022-09-03 07:44:23

这两个调用都是正确的:

Collectors.groupingBy((String s)->s.toLowerCase(),Collectors.counting());
Collectors.groupingBy((String s)->s.toLowerCase(Locale.ENGLISH),Collectors.counting());

从那以后,为什么下面的一个是错误的:

Collectors.groupingBy(String::toLowerCase,Collectors.counting());

毕竟不能对应第二个...那么为什么IntelliJ说?String::toLowerCaseReference to 'toLowerCase' is ambiguous, both 'toLowerCase(Locale)' and 'toLowerCase()' match

String::toLowerCase必须明确地解决还是我错过了什么?(String s)->s.toLowerCase()

当然,如果我给IntelliJ更多的上下文,比如:

Collector<String,?,Map<String,Long>> c = Collectors.groupingBy(String::toLowerCase,Collectors.counting());

这是正确的,但是在Java 10 var推理类型上下文中,这是错误的:

var c = Collectors.groupingBy(String::toLowerCase,Collectors.counting());

我知道编译器无法推断出的输入类型。如果我写:counting

Collector<String,?,Long> counter = Collectors.counting();
var c = Collectors.groupingBy(String::toLowerCase,counter);

它是正确的。因此,为什么编译器不能推断出唯一可接受的形式?

-------编辑--------

我交替使用IntelliJ /编译器,只是因为我首先使用IntelliJ,并且报告的错误是:

Reference to 'toLowerCase' is ambiguous, both 'toLowerCase(Locale)' and 'toLowerCase()' match

编译器的错误更加不可读(但包含更多关于推理失败原因的提示),如下所示:

Demo.java:31: error: incompatible types: cannot infer type-variable(s) T#1,K,A,D,CAP#1,T#2
        Collectors.groupingBy(String::toLowerCase,Collectors.counting());
                             ^
    (argument mismatch; invalid method reference
      incompatible types: Object cannot be converted to Locale)
  where T#1,K,A,D,T#2 are type-variables:
    T#1 extends Object declared in method <T#1,K,A,D>groupingBy(Function<? super T#1,? extends K>,Collector<? super T#1,A,D>)
    K extends Object declared in method <T#1,K,A,D>groupingBy(Function<? super T#1,? extends K>,Collector<? super T#1,A,D>)
    A extends Object declared in method <T#1,K,A,D>groupingBy(Function<? super T#1,? extends K>,Collector<? super T#1,A,D>)
    D extends Object declared in method <T#1,K,A,D>groupingBy(Function<? super T#1,? extends K>,Collector<? super T#1,A,D>)
    T#2 extends Object declared in method <T#2>counting()
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?

答案 1

这是编译器的“弱点”,至少在这个JEP到位之前是这样。

我已经在这里回答了几乎相同的问题。JDK核心开发人员也有另一个答案。

还有另一个问题与你的问题非常接近。

重要的是,已知这有时会导致问题,但有一个微不足道的解决方案 - 根据.lambdaJLS


答案 2

我的猜测是编译器在类中发现了两个出现的,因此它决定首先从第二个参数推断,该参数解析为。这会导致编译器引发错误,因为它找不到任何接受 .toLowerCaseStringCollectors.counting()ObjecttoLowerCase()Object

如果我们尝试定义一个方法将其用作替换:

static String toLowerCase(String s) {
    return s.toLowerCase();
}

然后,以下内容将起作用:

Collectors.groupingBy(Test::toLowerCase, Collectors.counting()); // compiles ok

但是,如果我们引入另一个过载,问题再次出现:

static String toLowerCase(String s) {
    return s.toLowerCase();
}

static String toLowerCase(String s, Locale locale) {
    return s.toLowerCase(locale);
}

Collectors.groupingBy(Test::toLowerCase,Collectors.counting()); // fails again

推荐