This came up as I was writing a custom Spliterator
. I know I should override estimateSize
if I know the size, even an approximative one. And usually, I do. But then there is getExactSizeIfKnown
and I understand it's default implementation:
default long getExactSizeIfKnown() {
return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}
Now, suppose I am working on an ArrayListSpliterator
(I understand it already exists, that is not the point). Should I override getExactSizeIfKnown
or estimateSize
or may be even both?
Internally, I guess getExactSizeIfKnown
is actually called, not estimateSize
- since the first one delegates to the second. Taking into consideration that theoretically I am working on a ArrayListSpliterator
, will not overriding getExactSizeIfKnown
actually just make me pay for one extra method call - the detour getExactSizeIfKnown
-> estimateSize
?
The answer to “Should I override getExactSizeIfKnown
or estimateSize
or may be even both?” is, you must implement estimateSize
as it is abstract
. You may additionally override the default
method getExactSizeIfKnown
if you see a reason.
Internally, I guess
getExactSizeIfKnown
is actually called, notestimateSize
- since the first one delegates to the second.
It’s not that simple. Be prepared for code calling getExactSizeIfKnown
because it may utilize that number only if being exact and hasn’t checked the characteristics. But at the same time there can be other code calling estimateSize
, either because it wants an estimate or because it will processes the characteristics at another place. The fact that one has a default
implementation that may delegate to the other under a certain condition doesn’t say anything about the caller. These methods have different semantics.
Taking into consideration that theoretically I am working on a
ArrayListSpliterator
, will not overridinggetExactSizeIfKnown
actually just make me pay for one extra method call - the detourgetExactSizeIfKnown
->estimateSize
?
It’s likely that the conditional hurts more than a delegation call, but if your specific Spliterator
invariably returns the same characteristics, the JVM’s optimizer likely eliminates any overhead connected with that. So it’s the usual trade-off, here, a tiny potential performance benefit over a tiny development effort (for providing an additional method just returning a known number).
If the calculation of the size is not trivial you would end up at delegation anyway, as you don’t want duplication of nontrivial code. And if your class is designed in a way that the SIZED
characteristic is not always present, you would do exactly the same as the default
method anyway.