2

The following code compiles and runs correctly when using the 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 );
    }
}

When compiled using javac, the following errors are emitted:

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

It appears there are two issues here

  • a protected method cannot be used as a method reference
  • it's impossible to select the correct uncheck(...) method based solely on the return type (ie. either T or void)

The overall question is "why is there a behaviour difference?", but perhaps it can be broken down into:

  • Is javac being too strict with the method reference restriction, or is the Eclipse compiler being lax here?
  • Is javac correctly determining that the method resolution is ambiguous, or does it simply lack the smarts of the Eclipse compiler to correctly determine which method should be selected?
jr.
  • 1,699
  • 14
  • 31

1 Answers1

4

This is a known bug in javac compiler (see JDK-8139836) which is finally fixed in OpenJDK 1.9ea-b89. You may download the Java9 early access build and see that it compiles your code normally. This bug affects method references only. You can replace it with lambda expression. It's not much longer and compiles fine in both ECJ and javac:

return (Foo)uncheck( () -> super.clone() );
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
  • Is this bug also the cause of javac being able to determine which method is being called, or does it only apply to the invalid method reference? – jr. Nov 10 '15 at 04:35
  • 2
    @studro, I guess inability to decide which method to call is the consequence of the original bug. If you remove `uncheck` overload (leaving only `Callable`), you will still have a compilation error in javac. – Tagir Valeev Nov 10 '15 at 04:39
  • 3
    I didn’t know that there is a bug report for [this issue](http://stackoverflow.com/q/33107500/2711488). I’ve added the link to its answer. – Holger Nov 10 '15 at 09:56
  • 2
    @Holger, it was submitted at the same day as that question (Oct 13th). So probably it was submitted by that question author or some passer-by. Webbug bugs publicly appear on the OpenJDK JIRA later as they are manually premoderated, thus probably it still was not visible that time. – Tagir Valeev Nov 10 '15 at 10:01
  • 2
    I noticed the date and also considered the possibility that the questioner filed the report. But even then, adding the link is valuable for future readers. How did you notice the bug report? – Holger Nov 10 '15 at 10:04
  • 2
    @Holger, just searched the ["method reference protected"](https://bugs.openjdk.java.net/browse/JDK-8139836?jql=text%20~%20%22method%20reference%20protected%22): this bug is the third result currently. No magic. Probably this question can be closed as duplicate of that one? – Tagir Valeev Nov 10 '15 at 10:07