Java var 和推理类型歧义
Java var and inference type ambiguity
两个调用都是正确的:
Collectors.groupingBy((String s)->s.toLowerCase(),Collectors.counting());
Collectors.groupingBy((String s)->s.toLowerCase(Locale.ENGLISH),Collectors.counting());
既然如此,为什么下面这个是错误的:
Collectors.groupingBy(String::toLowerCase,Collectors.counting());
毕竟String::toLowerCase
不能对应第二个...那为什么IntelliJ说Reference 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 inference type context 中是错误的:
var c = Collectors.groupingBy(String::toLowerCase,Collectors.counting());
我了解编译器无法推断 counting
的输入类型。如果我写:
Collector<String,?,Long> counter = Collectors.counting();
var c = Collectors.groupingBy(String::toLowerCase,counter);
它是正确的。因此,为什么编译器无法推断出唯一可接受的形式?
--------编辑--------
我交替使用 IntelliJ/compiler 只是因为我首先使用 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 ?
我的猜测是编译器在 String
class 中发现了两次 toLowerCase
,因此它决定首先从第二个参数 Collectors.counting()
推断,解析为 Object
。这导致编译器抛出错误,因为它找不到任何接受 Object
.
的 toLowerCase()
方法
如果我们尝试定义一个方法来使用它作为替代:
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
这是编译器的“弱点”,至少在 this JEP is in place 之前是这样。
我已经回答了几乎完全相同的问题 . There is also another answer from JDK core developers too。
还有和你的很接近
重要的是,已知这有时会导致问题,但有一个简单的解决方案 - 使用 lambda
,因此使用 explicit 类型,根据 JLS
.
两个调用都是正确的:
Collectors.groupingBy((String s)->s.toLowerCase(),Collectors.counting());
Collectors.groupingBy((String s)->s.toLowerCase(Locale.ENGLISH),Collectors.counting());
既然如此,为什么下面这个是错误的:
Collectors.groupingBy(String::toLowerCase,Collectors.counting());
毕竟String::toLowerCase
不能对应第二个...那为什么IntelliJ说Reference 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 inference type context 中是错误的:
var c = Collectors.groupingBy(String::toLowerCase,Collectors.counting());
我了解编译器无法推断 counting
的输入类型。如果我写:
Collector<String,?,Long> counter = Collectors.counting();
var c = Collectors.groupingBy(String::toLowerCase,counter);
它是正确的。因此,为什么编译器无法推断出唯一可接受的形式?
--------编辑--------
我交替使用 IntelliJ/compiler 只是因为我首先使用 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 ?
我的猜测是编译器在 String
class 中发现了两次 toLowerCase
,因此它决定首先从第二个参数 Collectors.counting()
推断,解析为 Object
。这导致编译器抛出错误,因为它找不到任何接受 Object
.
toLowerCase()
方法
如果我们尝试定义一个方法来使用它作为替代:
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
这是编译器的“弱点”,至少在 this JEP is in place 之前是这样。
我已经回答了几乎完全相同的问题
还有
重要的是,已知这有时会导致问题,但有一个简单的解决方案 - 使用 lambda
,因此使用 explicit 类型,根据 JLS
.