有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

仅在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) 个答案

  1. # 1 楼答案

    在某些情况下可以观察到不同行为的根本原因是:Eclipse使用自己的编译器“ECJ”,即has been explained before。相比之下,Maven通常会委托给javac,尽管it can be told to use ECJ,如果您想确保Maven构建显示与Eclipse中相同的结果的话

    当然,两个编译器都应该遵守JLS,因此表现出相同的行为,但实际上,由于JLS的复杂性,任何真实世界的编译器都有bug,从而导致编译器之间的偏差


    对于这个特定的差异,我不明白为什么javac会根据orElse()的参数得到不同的结果。请注意签名:

    public final class Optional<T> {
        ....
        public T orElse(T other)
        ....
    }
    

    请注意,只有类是泛型的,而不是方法。由于TList<String>(来自list的声明),orElse也返回一个List<String>,因此在这个阶段不涉及类型推断。因为我们知道一旦我们有了List<String>,尾部应该可以很好地编译,所以没有任何编译器应该报告错误的理由

    唯一的问题是将原始List作为参数传递,但这完全由该位置的未检查警告处理

    我很惊讶地看到javac由于原始类型的问题而拒绝了一个程序,因为这个领域的大多数问题都是由https://bugs.openjdk.java.net/browse/JDK-8026527引起的,而这意味着允许不应该被拒绝的程序

    编辑:为了完整性:我假设以下导入:

    import java.util.*;
    import static java.util.stream.Collectors.toList;
    

    我们需要一个toList的定义来完全确定会发生什么