问题
Since Java 5, we have the new java.lang.Iterable type that can be used in foreach loops as such:
for (Object element : iterable);
The Iterable contract does not specify whether its iterator() method can be called more than once before disposing of the Iterable. I.e., it is not clear whether the following can be expected to work for all Iterables
:
for (Object element : iterable);
for (Object element : iterable);
For instance, an Iterator
wrapping implementation cannot be used twice:
public class OneShotIterable<T> implements Iterable<T> {
private final Iterator<T> it;
public OneShotIterable(Iterator<T> it) {
this.it = it;
}
@Override
public Iterator<T> iterator() {
return it;
}
}
For most Iterables
, this is irrelevant, as they are in fact retro-fitted Collection API types such as List
, Set
, which already have well-defined contracts for their iterator()
methods.
My question is: Is my OneShotIterable
implementation violating some contract that I'm overlooking? In other words, will users of an Iterable
expect it to be reusable? If so, is there an "official" recommendation by the Java 5 expert group how to deal with such "one shot" Iterables
(e.g. throw an IllegalStateException
on a second call)?
回答1:
One precedent that I could find in the standard library is the DirectoryStream interface.
Its Javadoc contains the following passage (emphasis theirs):
While
DirectoryStream
extendsIterable
, it is not a general-purposeIterable
as it supports only a singleIterator
; invoking theiterator
method to obtain a second or subsequent iterator throwsIllegalStateException
.
To me, this suggests two things:
- The implied contract on Iterable is that you're supposed to be able to iterate more than once (perhaps even concurrently!)
- A boldface warning in the documentation coupled with throwing IllegalStateException is probably the best way to handle non-compliance in your own classes/interfaces.
回答2:
Not really an answer to my question, but Apache Commons Collections has addressed this issue in its IteratorUtils
class:
- IteratorUtils.asIterable(Iterator)
- IteratorUtils.asMultipleUseIterable(Iterator)
Both are factory methods for the IteratorIterable
type. The above distinction makes it clear that one must take care when wrapping Iterators
in Iterables
.
来源:https://stackoverflow.com/questions/15781739/is-there-any-official-contract-for-the-iterable-interface-with-respect-to-multip