The Iterator
simply provides an interface into some sort of stream, therefore not only is it perfectly possible for next()
to destroy data in some way, but it's even possible for the data in an Iterator
to be unique and irreplaceable.
We could come up with more direct examples, but an easy one is the Iterator
in DirectoryStream
. While a DirectoryStream
is technically Iterable
, it only allows one Iterator
to be constructed, so if you tried to do the following:
Path dir = ...
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
int count = length(stream.iterator());
for (Path entry: stream) {
...
}
}
You would get an exception in the foreach block, because the stream can only be iterated once. So in summary, it is possible for your length()
method to change objects and lose data.
Furthermore, there's no reason an Iterator
has to be associated with some separate data-store. Take for example an answer I gave a few months ago providing a clean way to select n
random numbers. By using an infinite Iterator
we are able to provide, filter, and pass around arbitrarily large amounts of random data lazily, no need to store it all at once, or even compute them until they're needed. Because the Iterator
doesn't back any data structure, querying it is obviously destructive.
Now that said, these examples don't make your method bad. Notice that the Guava library (which everyone should be using) provides an Iterators
class with exactly the behavior you detail above, called size()
to conform with the Collections Framework. The burden is then on the user of such methods to be aware of what sort of data they're working with, and avoid making careless calls such as trying to count the number of results in an Iterator
that they know cannot be replaced.