I'm testing the new closure features of Java 8; I'm wondering why this piece of code
public class Test8 {
private class A { int a;}
private class B { int b;}
interface IFA { void ifa(A param); }
interface IFB { void ifb(B param); }
private void forceA(A expr) { }
private void z(IFA fun) { System.out.println( "A"); fun.ifa( new A() ); }
private void z(IFB fun) { System.out.println( "B"); fun.ifb( new B() ); }
public void run() {
z( x -> forceA(x) );
}
public static void main(String args[]) { new Test8().run(); }
}
gives the error: both method z(IFA) in Test8 and method z(IFB) in Test8 match error
on z invocation in the run method
Isn't the compiler able to detect that the forceA
invocation forces x to be of type A and thus the correct z to use is z(IFA fun)
?
(a similar function is legal in C# using delegate; is there a way to get the same result in Java 8? )
Java 8 is still a work in progress. The latest spec does allow your code to work. The compiler implementation should catch up soon.
Nevertheless, this kind of overloading is not a good style. We have signatures
z( A->void )
z( B->void )
then when javac sees
z( arg->{ block } )
it's not apparent which z()
applies. Extra work must be done (by compiling block) to pick one.
We don't really care about how difficult it is to javac. The real issue is, when a human sees that code, the human has to dig deeper to understand which z()
is referred to. Not very readable.
As a rule of thumb, avoid overloading a method with functional interfaces of the same arity. Different arities are fine, there's no problem to disambiguate, for human or javac
z( arg->{...} )
z( (arg1,arg2)->{...} )
Another form of overloading is also blessed by the designers (Dan Smith etc) - same arity, same parameter types, but different return types
z( X->R1 )
z( X->R2 )
but I think it is pretty confusing too and I would avoid it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With