I am trying to mimic the java’s Function<T,R> by writing below code :
interface SFunction<T, G> { G apply(T t); default <Q> SFunction<T, Q> andThen(SFunction<? super G, ? extends Q> after) { return (T t) -> { return after.apply(apply(t)); }; // return new SFunction<T, Q>() { // @Override // public Q apply(T t) { // return after.apply(apply(t)); // } // }; } }
when I am writing below code in andThen
, it’s working fine (pointing to apply(T t)
of interface) and perfectly chaining the other functional implementations
snippet A return (T t) -> { return after.apply(apply(t)); };
But when writing below snippet, it’s falling into recursion, logically that’s correct
snippet B return new SFunction<T, Q>() { @Override public Q apply(T t) { return after.apply(apply(t)); } };
, but why in snippet A, after.apply(apply(t))
is calling outer apply(T t)
even though internally java implement the anonymous implementation.
Isn’t snippet A and B same internally and logically?
Thanks
Advertisement
Answer
It is important to note what method the apply(t)
in snippet B is actually referring to:
@Override public Q apply(T t) { // <--- it's referring to this method! return after.apply(apply(t)); // ^^^^^^^^ }
It is actually referring to the apply(T)
method that returns a Q
that you have just declared. It’s trying to call it recursively. But obviously that doesn’t work, because after.apply
doesn’t expect a Q
. The declaration of the Q apply(T)
method shadows the G apply(T)
method declared outside.
In the lambda’s case, you do not introduce a new identifier called apply
, so apply
can only mean the apply
on the SFunction<T, G>
object – the one on which andThen
is called.
To refer to the SFunction<T, G>
object’s apply
method in the SFunction<T, Q>
anonymous class, you can use a qualified this
expression:
return after.apply(SFunction.this.apply(t));
SFunction.this
refers to the SFunction<T, G>
object on which andThen
is called.
Now the two versions are logically the same, but internally, lambdas are very different from anonymous classes.