仅在maven上发生java泛型编译错误
我发现编译类时出现了一个问题,这个问题只发生在maven中,而不是Eclipse中
代码如下:
@Test
public void compliationFailOnMaven() {
Optional<List<String>> list = getDummyList();
List<Integer> hascodes = list.orElse(Collections.EMPTY_LIST).stream().map(value -> value.hashCode()).collect(toList());
assertThat(hascodes).isNotNull();
}
private Optional<List<String>> getDummyList() {
return Optional.ofNullable(new ArrayList<String>(0));
}
如果将此代码插入maven项目并尝试使用mvn clean test
执行它,则由于编译问题而失败:
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /java-tests/general-test/src/test/java/com/java8/stream/StreamTest.java:[113,125] incompatible types: java.lang.Object cannot be converted to java.util.List<java.lang.Integer>
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.844 s
[INFO] Finished at: 2015-11-19T18:07:36+01:00
[INFO] Final Memory: 26M/277M
[INFO] ------------------------------------------------------------------------
但是,如果您将这个项目导入eclipse,它可以编译并执行它,而不会出现任何问题
问题在于泛型的使用。如果我替换此行:
List<Integer> hascodes = list.orElse(Collections.EMPTY_LIST).stream().map(value -> value.hashCode()).collect(toList());
关于这一点:
List<Integer> hascodes = list.orElse(new ArrayList<String>(0)).stream().map(value -> value.hashCode()).collect(toList());
一切都可以在两种环境中工作:eclipse和maven
有人知道为什么会这样吗
为什么它们会产生不同的结果
我只安装了一个JVM,所以两者都使用相同的Java版本
# 1 楼答案
在某些情况下可以观察到不同行为的根本原因是:Eclipse使用自己的编译器“ECJ”,即has been explained before。相比之下,Maven通常会委托给
javac
,尽管it can be told to use ECJ,如果您想确保Maven构建显示与Eclipse中相同的结果的话当然,两个编译器都应该遵守JLS,因此表现出相同的行为,但实际上,由于JLS的复杂性,任何真实世界的编译器都有bug,从而导致编译器之间的偏差
对于这个特定的差异,我不明白为什么javac会根据
orElse()
的参数得到不同的结果。请注意签名:请注意,只有类是泛型的,而不是方法。由于
T
是List<String>
(来自list
的声明),orElse
也返回一个List<String>
,因此在这个阶段不涉及类型推断。因为我们知道一旦我们有了List<String>
,尾部应该可以很好地编译,所以没有任何编译器应该报告错误的理由唯一的问题是将原始
List
作为参数传递,但这完全由该位置的未检查警告处理我很惊讶地看到javac由于原始类型的问题而拒绝了一个程序,因为这个领域的大多数问题都是由https://bugs.openjdk.java.net/browse/JDK-8026527引起的,而这意味着允许不应该被拒绝的程序
编辑:为了完整性:我假设以下导入:
我们需要一个
toList
的定义来完全确定会发生什么