【问题标题】:Eclipse fails to compile generic code, but mvn compile worksEclipse 无法编译通用代码,但 mvn compile 有效
【发布时间】:2014-04-11 07:57:24
【问题描述】:

在带有 jdk 1.7 的 Eclipse Kepler 4.2 中,我在 Eclipse 中收到以下错误:

The method or(capture#2-of ?) in the type Optional<capture#2-of ?> is not applicable for the arguments (Object)

而运行mvn compile时编译成功。

如下所示:

package testit;

import java.util.Map;
import java.util.Map.Entry;

import com.google.common.base.Optional;

public class Test {

    private static final Object NO_VALUE = new Object();

    public void method(Map<String, ?> map) {
        for (Entry<String, ?> entry : map.entrySet()) {
            Optional.fromNullable(entry.getValue()).or(NO_VALUE);
//                                                  ^^ error here
        }
    }
}

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>my.test</groupId>
  <artifactId>testit</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
      <dependency>
          <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>13.0.1</version>
      </dependency>
  </dependencies>
  <build>
    <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>    
    </plugins>
  </build>
</project>

类似的代码在生产环境中运行了很长时间而没有错误(在这方面)。它在 Maven、Jenkins、Intelij 中编译,但不在 Eclipse 中。问题是为什么它不能在 Eclipse 中编译?

【问题讨论】:

  • +1 也在这里确认。在您的问题中提供好的示例代码做得很好。有趣的是,Eclipse 中嵌入的 Maven 也可以构建它。
  • 您能否检查一下Eclipse 中编译器的合规性设置是否适用于Java 7?
  • @robermann 在我的情况下,他们是。 Eclipse m2e 基于 POM 配置编译器合规性设置。

标签: java eclipse maven guava


【解决方案1】:

经过 Eclipse 团队的深入分析(顺便说一句,非常感谢!)他们对这个问题的回答如下

引用 Eclipse Bugzilla 的 Stephan Herrmann 的话:

此行不适用,原因如下:

类型推断从解析这个表达式开始:

Optional.fromNullable(entry.getValue())

在此表达式中,所有元素都可以按上述方式键入:

entry : 入口 entry.getValue:
capture#2-of ? fromNullable(..) : (capture#2-of ?) -&gt; Optional&lt;capture#2-of ?&gt;

简而言之:T 被推断为“capture#2-of ?”。推理成功。

只有在所有这些都已经决定之后,才进行解决 检查 .or(..) 方法调用。无理由填写 uninferred 用“对象”推断变量。

使用 Optional 类型的接收器,我们有这三个 “或”的重载:

可选或(可选)
capture#2-of ? or(Supplier&lt;? extends capture#2-of ?&gt; supplier)
capture#2-of ? or(capture#2-of ? defaultValue)

这些方法都不适用于 Object 类型的参数。 ecj随意选择第一种报错方式:

"类型中的方法or(可选) Optional 不适用于参数(对象)"

ecj 和 javac 之间的区别肯定由 提到javac的bug:https://bugs.openjdk.java.net/browse/JDK-8016207

正如那个错误中提到的,JLS 的未来更新可能 采用当前 javac 行为的一部分。直到这样的规范更新 发布后,ecj 唯一可靠的参考点是 JLS。在 这个规范我认为没有理由改变 ecj 的行为 这方面。

顺便说一句,规范的修复(不需要演员)是:

Optional.&lt;Object&gt;fromNullable(entry.getValue()).or(NO_VALUE);

现在这就是结论了。

【讨论】:

    【解决方案2】:

    Eclipse 编译器不是标准的 javac。它使用ECJ Compiler 这绝对是 Eclipse 编译器中的一个错误,因为 maven 使用标准 javac 来编译这就是它工作的原因。

    【讨论】:

    • 有传言说甚至 javac 有时也包含错误。
    • @JensSchauder 当然可以。但我会先质疑 Eclipse 编译器。
    • 我同意一般情况,但我看不出编译它有什么意义。
    • @JensSchauder 一个小的搜索揭示了这一点:15.12.2.8 任何尚未被推断的剩余类型变量然后被推断为具有类型 Object
    • @Eugene 所以你是说docs.oracle.com/javase/specs/jls/se7/html/… 的其余部分不适用?我会对为什么感兴趣,因为我什至不明白。
    【解决方案3】:

    您没有提出问题,所以我假设问题是:“谁是对的,如何使代码正常工作?”

    我会说 Eclipse 是对的。

    fromNullable 的结果有类型参数?,即存在一个类型T 但我们不知道。

    or 返回的Optional 必须与调用它的Optional 具有相同的类型参数,这也意味着它采用相同的未知类型T 作为参数。但是Object 可能与该类型兼容,也可能不兼容,因此失败是正确的。

    为了修复它,我认为以下更改应该有效:

    Optional.fromNullable((Object)entry.getValue()).or(NO_VALUE);
    

    强制转换将原本未知的类型参数绑定到 Object,这显然与调用 or 时的 Object 兼容。

    【讨论】:

    • 鉴于您回答的内容,特别是“所以失败是正确的”,您真的认为 Eclipse 是对的,而不是 Maven?
    • 哎呀是的。解决它。感谢您发现它。
    • 它提出了什么被定义为“正确”的问题。 Maven 只使用本地的javac,默认情况下这可能是正确的。 Eclipse 有自己的增量编译器,在我质疑 Oracle 的实现之前,我可能会质疑它。我想知道语言规范是否对此有看法。
    • @JensSchauder 感谢我忘记强调的关于遗漏问题的评论。问题在于代码在生产环境中运行了很长时间,并且构建在 Jenkins、maven、intelij 之上。我加入了这个项目,并在遇到错误的地方用 eclipse 检查了代码。添加演员表隐藏了问题。我宁愿找到其他解决方案。事实上,我配备 intelij 的同事只是在等着听到 eclipse 不能与代码相处,而 intelij 可以;)
    • @kubagruszka 在那种情况下:当 Intellij 似乎可用时,为什么你还在使用 Eclipse?
    猜你喜欢
    • 2021-11-20
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-14
    • 2012-11-10
    • 1970-01-01
    相关资源
    最近更新 更多