Let's see the code below, then you can see why?
class IntegerConsumer implements Consumer<Integer>, IntConsumer {
...
}
Any class can implement multi-interfaces, one is Consumer<Integer>
maybe implements another one is IntConsumer
. Sometimes occurs when we want to adapt IntConsumer
to Consumer<Integer>
and to save its origin type (IntConsumer
), then the code looks like as below:
class IntConsumerAdapter implements Consumer<Integer>, IntConsumer {
@Override
public void accept(Integer value) {
accept(value.intValue());
}
@Override
public void accept(int value) {
// todo
}
}
Note: it's the usage of Class Adapter Design Pattern.
THEN you can use IntConsumerAdapter
both as Consumer<Integer>
and IntConsumer
, for example:
Consumer<? extends Integer> consumer1 = new IntConsumerAdapter();
IntConsumer consumer2 = new IntConsumerAdapter();
Sink.OfInt
is a concrete usage of Class Adapter Design Pattern in jdk-8.The downside of Sink.OfInt#accept(Integer)
is clearly that JVM will throw a NullPointerException
when it accepts a null
value, so that is why Sink
is package visible.
189 interface OfInt extends Sink<Integer>, IntConsumer {
190 @Override
191 void accept(int value);
193 @Override
194 default void accept(Integer i) {
195 if (Tripwire.ENABLED)
196 Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
197 accept(i.intValue());
198 }
199 }
I found it why need to cast a Consumer<Integer>
to an IntConsumer
if pass a consumer like as IntConsumerAdapter
?
One reason is when we use a Consumer
to accept an int
the compiler needs to auto-boxing it to an Integer
. And in the method accept(Integer)
you need to unbox an Integer
to an int
manually.
In the other words, each accept(Integer)
does 2 additional operations for boxing/unboxing. It needs to improve the performance so it does some special checking in the algorithm library.
Another reason is reusing a piece of code. The body of OfInt#forEachRemaining(Consumer) is a good example of applying Adapter Design Pattern for reusing OfInt#forEachRenaming(IntConsumer).
default void forEachRemaining(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
// action's implementation is an example of Class Adapter Design Pattern
// |
forEachRemaining((IntConsumer) action);
}
else {
// method reference expression is an example of Object Adapter Design Pattern
// |
forEachRemaining((IntConsumer) action::accept);
}
}