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.