大家早上好,
我已经挣扎了一段时间,理解为什么以下的代码片段不能在Eclipse Neon(JDT 3.12.3.v20170301-0400)中编译,但与javac或Eclipse Mars完美编译:
public class TestLambda {
protected static <K, V> Map<K, V> newMap(final Function<K, V> loader) {
return new HashMap<>();
}
private final Map<Integer, Integer> working = newMap(key -> {
final List<String> strings = new ArrayList<>();
final String[] array = strings.toArray(new String[strings.size()]);
foo(array);
return null;
});
private final Map<Void, Void> notWorking = newMap(key -> {
final List<String> strings = new ArrayList<>();
// This line seems to be the root of all evils
foo(strings.toArray(new String[strings.size()]));
return null;
});
private void foo(final String[] x) {}
private void foo(final Integer[] x) {}
}
Eclipse编译器说&#34;类型不匹配:无法从Map<Object,Object>
转换为Map<Void,Void>
&#34;。
似乎无法知道必须调用哪个foo方法......
我做错了吗?
提前感谢您的帮助
答案 0 :(得分:0)
即使使用最新版本的Eclipse Oxygen,我也可以重现这个问题。任何{8}版本的Java 8或Java 9 beta都不会出现此问题。
我们可以清楚地得出结论,这是一个错误和一个奇怪的错误。
首先,这里没有歧义。 javac
的两次调用都必须以foo
结束,事实上,Eclipse不会报告歧义问题。
其次,foo(String[])
调用对此lambda表达式的功能类型没有影响。
如果我们将行foo
更改为foo(strings.toArray(new String[strings.size()]));
,我们会在foo(strings.toArray());
处收到真正的错误,因为不存在foo
,但类型推断会正确解析{{ 1}}表示lambda表达式,foo(Object[])
表示Function<Void, Void>
的返回类型。
我们还可以通过将Map<Void, Void>
声明更改为
newMap
这会导致foo
次调用都出错,因为private void foo(final Serializable[] x) {}
private void foo(final CharSequence[] x) {}
与这两种方法兼容,foo
和String[]
之间没有关系,但是类型推断Serializable
调用未受影响并解析为
CharSequence
正如所料。
最奇怪的是,只需交换newMap
方法的顺序就会使错误消失:
<Void, Void> Map<Void, Void> newMap(Function<Void, Void>)
编译好。
背后有一种模式。只要最后声明的一个适用到foo
调用,您就可以拥有所需的public class TestLambda {
protected static <K, V> Map<K, V> newMap(final Function<K, V> loader) {
return new HashMap<>();
}
private final Map<Integer, Integer> working = newMap(key -> {
final List<String> strings = new ArrayList<>();
final String[] array = strings.toArray(new String[strings.size()]);
foo(array);
return null;
});
private final Map<Void, Void> notWorking = newMap(key -> {
final List<String> strings = new ArrayList<>();
// This line seems to be the root of all evils
foo(strings.toArray(new String[strings.size()]));
return null;
});
private void foo(final Integer[] x) {}
private void foo(final String[] x) {}
}
次重载。它不必是最终调用的最具体的一个,例如,在课程结束时放置另一个foo
也将解决问题。
该模式肯定没有匹配的Java语言规则......