Weird implementation of tryAdvance in Spliterator.OfInt

379 Views Asked by At

How does it work? How can Consumer<? super Integer> be cast to IntConsumer??

default boolean tryAdvance(Consumer<? super Integer> action) {
    if (action instanceof IntConsumer) {
        return tryAdvance((IntConsumer) action);
    }
    else {
        if (Tripwire.ENABLED)
            Tripwire.trip(getClass(),
                      "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
        return tryAdvance((IntConsumer) action::accept);
    }
}
2

There are 2 best solutions below

0
On BEST ANSWER

Your question isn’t quite clear as there are two type casts in the posted code.

The first one checks via instanceof whether the Consumer<? super Integer> also implements IntConsumer and does an ordinary type cast then, assuming that a class implementing Consumer and IntConsumer at the same time will do that with the same semantic. Compare with the documentation:

Implementation Requirements:

If the action is an instance of IntConsumer then it is cast to IntConsumer and passed to tryAdvance(java.util.function.IntConsumer); otherwise the action is adapted to an instance of IntConsumer, by boxing the argument of IntConsumer, and then passed to tryAdvance(java.util.function.IntConsumer).

So the first instanceof check and type cast are the first part of the contract, avoiding boxing if the action argument implements both interfaces.

The second type cast is part of the described adaptation to a boxing IntConsumer whereas the boxing is implied by the method reference (IntConsumer) action::accept. This method reference refers to the method void accept(T t) (where T := ? super Integer) which can be adapted to the function signature of IntConsumer, as described by Brian Goetz. Since this functional signature does not only fulfill the signature of IntConsumer but also (of course) the signature of Consumer<? super Integer> the type cast is needed to disambiguate between the overloaded tryAdvance methods. It would be unnecessary when using the equivalent lambda expression

return tryAdvance((int i)->c.accept(i));
0
On

The cast is providing a target type for the bound method reference action::accept, which is equivalent to the lambda x -> action.accept(x). The IntConsumer target type causes this lambda (which would prefer to accept an Integer) to be adapted to accept an int (which will cause the argument to be implicitly boxed before passing it to action.accept()).