COLLECTIONS-213. Added multiple use support to IteratorIterable.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1127604 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Brent Worden 2011-05-25 18:04:29 +00:00
parent 936fd069c7
commit 4499cf0862
4 changed files with 150 additions and 11 deletions

View File

@ -759,7 +759,8 @@ public class IteratorUtils {
}
/**
* Gets an iterable that wraps an iterator.
* Gets an iterable that wraps an iterator. The returned iterable can be
* used for a single iteration.
*
* @param iterator the iterator to use, not null
* @return a new, single use iterable
@ -769,7 +770,22 @@ public class IteratorUtils {
if (iterator == null) {
throw new NullPointerException("Iterator must not be null");
}
return new IteratorIterable<E>(iterator);
return new IteratorIterable<E>(iterator, false);
}
/**
* Gets an iterable that wraps an iterator. The returned iterable can be
* used for multiple iterations.
*
* @param iterator the iterator to use, not null
* @return a new, multiple use iterable
* @throws NullPointerException if iterator is null
*/
public static <E> Iterable<E> asMultipleUseIterable(Iterator<? extends E> iterator) {
if (iterator == null) {
throw new NullPointerException("Iterator must not be null");
}
return new IteratorIterable<E>(iterator, true);
}
/**

View File

@ -15,11 +15,47 @@ package org.apache.commons.collections.iterators;
import java.util.Iterator;
import org.apache.commons.collections.ResettableIterator;
/**
* Adapter to make an {@link Iterator Iterator} instance appear to be an
* {@link Iterable Iterable} instance. Unlike normal iterable instance, the
* {@link #iterator()} method always returns the same iterator instance. This
* prohibits this iterator to be only usable for one iterative operation.
* {@link Iterable Iterable} instance. The iterable can be constructed in one
* of two variants: single use, multiple use.
*
* <p>
* In the single use iterable case, the iterable is only usable for one
* iterative operation over the source iterator. Subsequent iterative
* operations use the same, exhausted source iterator. To create a single use
* iterable, construct a new {@link IteratorIterable} using a {@link Iterator}
* that is NOT a {@link ResettableIterator} iterator:
* <pre>
* Iterator<Integer> iterator = // some non-resettable iterator
* Iterable<Integer> iterable = new IteratorIterable<Integer>(iterator);
* </pre>
* </p>
*
* <p>
* In the multiple use iterable case, the iterable is usable for any number of
* iterative operations over the source iterator. Of special note, even though
* the iterable supports multiple iterations, it does not support concurrent
* iterations. To implicitly create a multiple use iterable, construct a new
* {@link IteratorIterable} using a {@link ResettableIterator} iterator:
* <pre>
* Integer[] array = {Integer.valueOf(1),Integer.valueOf(2),Integer.valueOf(3)};
* Iterator<Integer> iterator = IteratorUtils.arrayIterator(array); // a resettable iterator
* Iterable<Integer> iterable = new IteratorIterable<Integer>(iterator);
* </pre>
* </p>
*
* <p>
* A multiple use iterable can also be explicitly constructed using any
* {@link Iterator} and specifying <code>true</code> for the
* <code>multipleUse</code> flag:
* <pre>
* Iterator<Integer> iterator = // some non-resettable iterator
* Iterable<Integer> iterable = new IteratorIterable<Integer>(iterator, true);
* </pre>
* </p>
*
* @since Commons Collections 4.0
* @version $Revision: $ $Date: $
@ -47,9 +83,12 @@ public class IteratorIterable<E> implements Iterable<E> {
};
}
/** the iterator being used. */
private final Iterator<E> iterator;
/** the iterator being adapted into an iterable. */
private final Iterator<? extends E> iterator;
/** the iterator parameterized as the {@link #iterator()} return type. */
private final Iterator<E> typeSafeIterator;
/**
* Constructs a new <code>IteratorIterable</code> that will use the given
* iterator.
@ -57,8 +96,24 @@ public class IteratorIterable<E> implements Iterable<E> {
* @param iterator the iterator to use.
*/
public IteratorIterable(Iterator<? extends E> iterator) {
this(iterator, false);
}
/**
* Constructs a new <code>IteratorIterable</code> that will use the given
* iterator.
*
* @param iterator the iterator to use.
* @param multipleUse <code>true</code> if the new iterable can be used in multiple iterations
*/
public IteratorIterable(Iterator<? extends E> iterator, boolean multipleUse) {
super();
this.iterator = createTypesafeIterator(iterator);
if (multipleUse && !(iterator instanceof ResettableIterator)) {
this.iterator = new ListIteratorWrapper<E>(iterator);
} else {
this.iterator = iterator;
}
this.typeSafeIterator = createTypesafeIterator(this.iterator);
}
/**
@ -67,6 +122,9 @@ public class IteratorIterable<E> implements Iterable<E> {
* @return the iterator
*/
public Iterator<E> iterator() {
return iterator;
if (iterator instanceof ResettableIterator) {
((ResettableIterator<? extends E>)iterator).reset();
}
return typeSafeIterator;
}
}

View File

@ -61,6 +61,8 @@ public class TestIteratorUtils extends BulkTest {
assertEquals(expected, actual.intValue());
++expected;
}
// insure iteration occurred
assertTrue(expected > 0);
// single use iterator
for(Integer actual : iterable) {
@ -76,6 +78,41 @@ public class TestIteratorUtils extends BulkTest {
// success
}
}
public void testAsMultipleIterable() {
List<Integer> list = new ArrayList<Integer>();
list.add(Integer.valueOf(0));
list.add(Integer.valueOf(1));
list.add(Integer.valueOf(2));
Iterator<Integer> iterator = list.iterator();
Iterable<Integer> iterable = IteratorUtils.asMultipleUseIterable(iterator);
int expected = 0;
for(Integer actual : iterable) {
assertEquals(expected, actual.intValue());
++expected;
}
// insure iteration occurred
assertTrue(expected > 0);
// multiple use iterator
expected = 0;
for(Integer actual : iterable) {
assertEquals(expected, actual.intValue());
++expected;
}
// insure iteration occurred
assertTrue(expected > 0);
}
public void testAsMultipleIterableNull() {
try {
IteratorUtils.asMultipleUseIterable(null);
fail("Expecting NullPointerException");
} catch (NullPointerException ex) {
// success
}
}
public void testToList() {
List<Object> list = new ArrayList<Object>();

View File

@ -36,19 +36,47 @@ public class TestIteratorIterable extends BulkTest {
super(name);
}
public void testIterator() {
private Iterator<Integer> createIterator() {
List<Integer> list = new ArrayList<Integer>();
list.add(Integer.valueOf(0));
list.add(Integer.valueOf(1));
list.add(Integer.valueOf(2));
Iterator<Integer> iter = list.iterator();
return iter;
}
public void testIterator() {
Iterator<Integer> iter = createIterator();
Iterable<Number> iterable = new IteratorIterable<Number>(iter);
// first use
verifyIteration(iterable);
// second use
for (Number actual : iterable) {
fail("should not be able to iterate twice");
}
}
public void testMultipleUserIterator() {
Iterator<Integer> iter = createIterator();
Iterable<Number> iterable = new IteratorIterable<Number>(iter, true);
// first use
verifyIteration(iterable);
// second use
verifyIteration(iterable);
}
private void verifyIteration(Iterable<Number> iterable) {
int expected = 0;
for (Number actual : iterable) {
assertEquals(expected, actual.intValue());
++expected;
}
assertTrue(expected > 0);
}
}