Eclipse无法编译通用代码,但mvn编译有效

时间:2014-04-11 07:57:24

标签: java eclipse maven guava

在带有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中编译?

3 个答案:

答案 0 :(得分:6)

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

来自Eclipse Bugzilla的Stephan Herrmann:

  

此行不适用于以下原因:

     

类型推断首先解析此表达式:

     

Optional.fromNullable(entry.getValue())

     

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

     

条目:条目entry.getValue:
  capture#2-of ? fromNullable(..) : (capture#2-of ?) ->   Optional<capture#2-of ?>

     

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

     

只有在所有这些决定之后,才能解决问题   检查.or(..)方法调用。没有理由填写未推断的   使用&#34; Object&#34;。

推理变量      

使用Optional类型的接收器,我们有这三个   过度的&#34;或&#34;:

     

可选或(可选)
  capture#2-of ? or(Supplier<? extends capture#2-of ?> supplier)
  capture#2-of ? or(capture#2-of ? defaultValue)

     

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

     

&#34;方法或类型中的(可选)   可选不适用于参数(对象)&#34;

     

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

     

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

     顺便说一下,规范修正(不需要演员)是:

     

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

现在这将是结论。

答案 1 :(得分:1)

你没有提出问题,所以我假设了一个问题:&#34;谁是对的,以及如何使代码有效?&#34;

我说Eclipse是对的。

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

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

为了解决这个问题,我认为以下更改应该有效:

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

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

答案 2 :(得分:1)

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