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?