2

以下代码在使用 Eclipse Compiler for Java 时可以正确编译和运行。

package org.sandbox;

public final class ExceptionUtils
{
    private ExceptionUtils(){}

    @FunctionalInterface
    public interface Runnable
    {
        void run() throws Exception;
    }

    @FunctionalInterface
    public interface Callable<T>
    {
        T call() throws Exception;
    }

    public static void uncheck( final Runnable r )
    {
        try
        {
            r.run();
        }
        catch( final Exception e )
        {
            throw new RuntimeException( e );
        }
    }

    public static <T> T uncheck( final Callable<T> c )
    {
        try
        {
            return c.call();
        }
        catch( final Exception e )
        {
            throw new RuntimeException( e );
        }

    }
}

...

package org.sandbox;

import static org.sandbox.ExceptionUtils.uncheck;

public class Foo
{
    private String bar;

    public String getBar()
    {
        return bar;
    }

    public void setBar( final String bar )
    {
        this.bar = bar;
    }

    @Override
    public Foo clone()
    {
        return (Foo)uncheck( super::clone );
    }
}

使用 javac 编译时,会发出以下错误:

org\sandbox\Foo.java:22: error: reference to uncheck is ambiguous
        return (Foo)uncheck( super::clone );
                    ^
  both method <T>uncheck(Callable<T>) in ExceptionUtils and method uncheck(Runnable) in ExceptionUtils match
  where T is a type-variable:
    T extends Object declared in method <T>uncheck(Callable<T>)
org\sandbox\Foo.java:22: error: incompatible types: cannot infer type-variable(s) T
        return (Foo)uncheck( super::clone );
                           ^
    (argument mismatch; invalid method reference
      clone() has protected access in Object)
  where T is a type-variable:
    T extends Object declared in method <T>uncheck(Callable<T>)
2 errors

看来这里有两个问题

  • 受保护的方法不能用作方法引用
  • uncheck(...)仅根据返回类型(即 T 或 void)选择正确的方法是不可能的

总体问题是“为什么会有行为差异?”,但也许可以分解为:

  • javac 对方法引用限制是否过于严格,还是 Eclipse 编译器在这里松懈?
  • javac 是否正确确定方法解析不明确,或者它只是缺乏 Eclipse 编译器的智能来正确确定应该选择哪种方法?
4

1 回答 1

4

这是 javac 编译器中的一个已知错误(参见JDK-8139836),最终在 OpenJDK 1.9ea-b89 中得到修复。您可以下载Java9 早期访问版本并查看它是否可以正常编译您的代码。此错误仅影响方法引用。您可以将其替换为 lambda 表达式。它并不长,并且在 ECJ 和 javac 中都可以正常编译:

return (Foo)uncheck( () -> super.clone() );
于 2015-11-10T04:11:49.957 回答