Closed GoogleCodeExporter closed 8 years ago
I'm sorry, the EmptyIterator class does not actually exist, of course. It is an
anonymous class in the Iterators utils. You got the idea, though.
Original comment by Robin...@gmail.com
on 19 Aug 2009 at 8:23
I think the exception is correct. UnsupportedOperationException means there is
no
possible state or argument for which this operation could work, on any instance
of
this concrete type. IllegalStateException means that there exists some state
that an
instance of this concrete type could be in for which the operation would
succeed. Your
test should simply tolerate either type.
Original comment by kevin...@gmail.com
on 19 Aug 2009 at 11:40
I agree that UOE is inconvenient for your sample use case and similar cases.
Another
example: a mutable collection that stores its contents in a lazily allocated
array.
Once the array is allocated, a call to iterator() returns an iterator over the
array.
But before then, it makes sense to use emptyIterator(). However, this means that
the result of iterator().remove() on an empty collection has two different
results,
depending upon whether the collection ever contained elements:
- fresh empty collection: UOE
- cleared collection: ISE
It's certainly true that the iterator doesn't have its own "state," and it
would have
been defensible (if impractical) for Java to demand that all empty iterators
throw
UOE instead of ISE, but that's not how the Java collections behave. Perhaps it
makes
sense to argue that the "state" is the state of the underlying collection at
the time
of the iterator() call, but I'm not sure I buy that, myself. More convincing
to me
is the consistency argument.
Original comment by cpov...@google.com
on 20 Aug 2009 at 12:48
It is certainly correct for any subclass of UnmodifiableIterator to conform to
its
superclass interface and thus always throw an UnsupportedOperationException. My
argument is that the EmptyIterator shouldn't be a descendent of
UnmodifiableIterator
in the first place.
> ... UnsupportedOperationException means there is no
> possible state or argument for which this operation could work ...
Kind of correct -- at least for some sane and well defined state, which
complies with
the expected preconditions of the respective operation, so that invariants and
postconditions of that same operation can hold (even if that operation was
"panic" or
"chaos"). An IllegalStateException would be the one and only correct indicator
for
non-compliance.
> ... IllegalStateException means that there exists some state that an
> instance of this concrete type could be in for which the operation would
succeed ...
This is certainly incorrect. An IllegalStateException does not imply the
existence of
a legal state or its producibility -- just like an
UnsupportedOperationException does
not imply there is a supported alternative.
The one state where this operation could succeed can never be, since no
instance has
that state nor can it ever change to it -- a fact, bound to the concrete
implementation rather than the interface, and a random decision.
Another argument:
If I had some kind of Iterator over an arbitrarily sized collection, I wouldn't
want
that Iterator to throw an UnsupportedOperationException just because I missed
to call
next() before remove(), regardless of whether the collection is empty. In fact,
I
wouldn't want that iterator to consider the size of the collection at all. This
stipulation for the explicit EmptyIterator to always throw the
UnsupportedOperationException is introduced by the inheritence from
UnmodifiableIterator and for no sufficient reasen. It is only legal for this
particular hierarchy and only in concrete cases where the client is aware of the
implementation. In any other case, I consider this a bug... fortunately an
itsy-bitsy-tiny one, so never mind.
Original comment by Robin...@gmail.com
on 20 Aug 2009 at 2:56
The correct emptyIterator.remove() behavior, as I see it, varies based on the
iterator the same collection would return if nonempty. If the nonempty iterator
would be immutable, then remove() should throw UOE. If the nonempty iterator
would
be mutable, then remove() should throw ISE. Consistency über alles.
This doesn't address the question of whether many Google Collections users are
implementing their own mutable collection classes with special-case iterators
for
empty. If not, two separate public empty-iterator methods may not be worth the
API
bloat.
Original comment by cpov...@google.com
on 20 Aug 2009 at 3:08
> ... An IllegalStateException would be the one and only correct indicator for
non-compliance.
We're talking about Iterator#remove() here, which may only be called once per
successful call to Iterator#next() -- anything else resembles non-compliance.
Original comment by Robin...@gmail.com
on 20 Aug 2009 at 3:10
IllegalStateException would even be the correct throw for UnmodifiableIterators,
since remove() can never be called if next() cannot be called.
Original comment by Robin...@gmail.com
on 20 Aug 2009 at 3:14
For an empty iterator spawned from an immutable collection, I'm not sure I'd
argue
against either exception. UOE feels like the "stronger" exception to me, the
one
that suggests "even with a different instance of this class, remove() wouldn't
work."
Thus, I prefer it. But I admit that that's as much opinion as fact. Hence, I've
focused on the question of "Is it a good use of API space to have two methods?"
In short, I can see your argument that ISE is always acceptable, and I can see
Kevin's that UOE is always acceptable. In principle, I'd rather be able to
choose,
but I don't know that the two methods would pull their weight.
Original comment by cpov...@google.com
on 20 Aug 2009 at 3:33
Original issue reported on code.google.com by
Robin...@gmail.com
on 19 Aug 2009 at 7:50