无效的方法引用/模糊引用(javac / ecj行为差异)

时间:2015-11-10 00:52:08

标签: lambda java-8 javac type-inference ecj

使用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

这里似乎有两个问题

  • 受保护的方法不能用作方法参考
  • 根据返回类型(即T或无效)选择正确的uncheck(...)方法是不可能的。

整体问题是&#34;为什么会出现行为差异?&#34;,但也许可以分解为:

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

1 个答案:

答案 0 :(得分:4)

这是javac编译器中的已知错误(请参阅JDK-8139836),最终在OpenJDK 1.9ea-b89中修复。您可以下载Java9 early access build并查看它是否正常编译代码。此错误仅影响方法引用。您可以用lambda表达式替换它。在ECJ和javac中,它的编写时间不长,编译得很好:

return (Foo)uncheck( () -> super.clone() );