toList() {
+ return IteratorUtils.toList(iterator());
+ }
+
+ @Override
+ public String toString() {
+ return IterableUtils.toString(iterable);
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/collections4/IterableUtils.java b/src/main/java/org/apache/commons/collections4/IterableUtils.java
index 7297e21f1..de5ae84b6 100644
--- a/src/main/java/org/apache/commons/collections4/IterableUtils.java
+++ b/src/main/java/org/apache/commons/collections4/IterableUtils.java
@@ -16,6 +16,13 @@
*/
package org.apache.commons.collections4;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.collections4.iterators.LazyIteratorChain;
+import org.apache.commons.collections4.iterators.UniqueFilterIterator;
+
/**
* Provides utility methods and decorators for {@link Iterable} instances.
*
@@ -24,105 +31,472 @@ package org.apache.commons.collections4;
*/
public class IterableUtils {
- /**
- * Default prefix used while converting an Iterable to its String representation.
- */
- private static final String DEFAULT_TOSTRING_PREFIX = "[";
+ // Chained
+ // ----------------------------------------------------------------------
/**
- * Default suffix used while converting an Iterable to its String representation.
+ * Combines two iterables into a single iterable.
+ *
+ * The returned iterable has an iterator that traverses the elements in {@code a},
+ * followed by the elements in {@code b}. The source iterators are not polled until
+ * necessary.
+ *
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param the element type
+ * @param a the first iterable
+ * @param b the second iterable
+ * @return a new iterable, combining the provided iterables
*/
- private static final String DEFAULT_TOSTRING_SUFFIX = "]";
+ @SuppressWarnings("unchecked")
+ public static Iterable chainedIterable(final Iterable extends E> a, final Iterable extends E> b) {
+ return chainedIterable(new Iterable[] {a, b});
+ }
/**
- * Default delimiter used to delimit elements while converting an Iterable
- * to its String representation.
+ * Combines three iterables into a single iterable.
+ *
+ * The returned iterable has an iterator that traverses the elements in {@code a},
+ * followed by the elements in {@code b} and {@code c}. The source iterators are
+ * not polled until necessary.
+ *
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param the element type
+ * @param a the first iterable
+ * @param b the second iterable
+ * @param c the third iterable
+ * @return a new iterable, combining the provided iterables
*/
- private static final String DEFAULT_TOSTRING_DELIMITER = ", ";
+ @SuppressWarnings("unchecked")
+ public static Iterable chainedIterable(final Iterable extends E> a,
+ final Iterable extends E> b,
+ final Iterable extends E> c) {
+ return chainedIterable(new Iterable[] {a, b, c});
+ }
+
+ /**
+ * Combines four iterables into a single iterable.
+ *
+ * The returned iterable has an iterator that traverses the elements in {@code a},
+ * followed by the elements in {@code b}, {@code c} and {@code d}. The source
+ * iterators are not polled until necessary.
+ *
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param the element type
+ * @param a the first iterable
+ * @param b the second iterable
+ * @param c the third iterable
+ * @param d the fourth iterable
+ * @return a new iterable, combining the provided iterables
+ */
+ @SuppressWarnings("unchecked")
+ public static Iterable chainedIterable(final Iterable extends E> a,
+ final Iterable extends E> b,
+ final Iterable extends E> c,
+ final Iterable extends E> d) {
+ return chainedIterable(new Iterable[] {a, b, c, d});
+ }
+
+ /**
+ * Combines the provided iterables into a single iterable.
+ *
+ * The returned iterable has an iterator that traverses the elements in the order
+ * of the arguments, i.e. iterables[0], iterables[1], .... The source iterators
+ * are not polled until necessary.
+ *
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param the element type
+ * @param iterables the iterables to combine
+ * @return a new iterable, combining the provided iterables
+ */
+ public static Iterable chainedIterable(final Iterable extends E>... iterables) {
+ return new AbstractIterable() {
+ @Override
+ public Iterator iterator() {
+ return new LazyIteratorChain() {
+
+ @Override
+ protected Iterator extends E> nextIterator(int count) {
+ if (count > iterables.length) {
+ return null;
+ } else {
+ return emptyIteratorIfNull(iterables[count - 1]);
+ }
+ }
+
+ };
+ }
+ };
+ }
+
+ // Filtered
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a view of the given iterable that only contains elements matching
+ * the provided predicate.
+ *
+ * The returned iterable's iterator does not supports {@code remove()}.
+ *
+ * @param the element type
+ * @param iterable the iterable to filter, may be null
+ * @param predicate the predicate used to filter elements, must not be null
+ * @return a filtered view on the specified iterable
+ * @throws NullPointerException if predicate is null
+ */
+ public static Iterable filteredIterable(final Iterable iterable, final Predicate super E> predicate) {
+ if (predicate == null) {
+ throw new NullPointerException("predicate must not be null.");
+ }
+
+ return new AbstractIterable() {
+ @Override
+ public Iterator iterator() {
+ return IteratorUtils.filteredIterator(emptyIteratorIfNull(iterable), predicate);
+ }
+ };
+ }
+
+ // Bounded
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a view of the given iterable that contains at most the given number
+ * of elements.
+ *
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param the element type
+ * @param iterable the iterable to limit, may be null
+ * @param maxSize the maximum number of elements, must not be negative
+ * @return a bounded view on the specified iterable
+ * @throws IllegalArgumentException if maxSize is negative
+ */
+ public static Iterable boundedIterable(final Iterable iterable, final int maxSize) {
+ if (maxSize < 0) {
+ throw new IllegalArgumentException("maxSize parameter must not be negative.");
+ }
+
+ return new AbstractIterable() {
+ @Override
+ public Iterator iterator() {
+ return IteratorUtils.boundedIterator(emptyIteratorIfNull(iterable), maxSize);
+ }
+ };
+ }
+
+ // Looping
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a view of the given iterable which will cycle infinitely over
+ * its elements.
+ *
+ * The returned iterable's iterator supports {@code remove()} if
+ * {@code iterable.iterator()} does. After {@code remove()} is called, subsequent
+ * cycles omit the removed element, which is no longer in {@code iterable}. The
+ * iterator's {@code hasNext()} method returns {@code true} until {@code iterable}
+ * is empty.
+ *
+ * @param the element type
+ * @param iterable the iterable to loop, may be null
+ * @return a view of the iterable, providing an infinite loop over its elements
+ */
+ public static Iterable loopingIterable(final Iterable iterable) {
+ return new AbstractIterable() {
+ @Override
+ public Iterator iterator() {
+ return new LazyIteratorChain() {
+ @Override
+ protected Iterator extends E> nextIterator(int count) {
+ if (iterable != null) {
+ if (isEmpty(iterable)) {
+ return null;
+ } else {
+ return iterable.iterator();
+ }
+ } else {
+ return null;
+ }
+ }
+ };
+ }
+ };
+ }
+
+ // Skipping
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a view of the given iterable that skips the first N elements.
+ *
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param the element type
+ * @param iterable the iterable to use, may be null
+ * @param elementsToSkip the number of elements to skip from the start, must not be negative
+ * @return a view of the specified iterable, skipping the first N elements
+ * @throws IllegalArgumentException if elementsToSkip is negative
+ */
+ public static Iterable skippingIterable(final Iterable iterable, final int elementsToSkip) {
+ if (elementsToSkip < 0) {
+ throw new IllegalArgumentException("elementsToSkip parameter must not be negative.");
+ }
+
+ return new AbstractIterable() {
+ @Override
+ public Iterator iterator() {
+ return IteratorUtils.skippingIterator(emptyIteratorIfNull(iterable), elementsToSkip);
+ }
+ };
+ }
+
+ // Transformed
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a transformed view of the given iterable where all of its elements
+ * have been transformed by the provided transformer.
+ *
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param the element type
+ * @param iterable the iterable to transform, may be null
+ * @param transformer the transformer , must not be null
+ * @return a transformed view of the specified iterable
+ * @throws NullPointerException if transformer is null
+ */
+ public static Iterable transformedIterable(final Iterable iterable, final Transformer super I, ? extends O> transformer) {
+ if (transformer == null) {
+ throw new NullPointerException("transformer must not be null.");
+ }
+
+ return new AbstractIterable() {
+ @Override
+ public Iterator iterator() {
+ return IteratorUtils.transformedIterator(emptyIteratorIfNull(iterable), transformer);
+ }
+ };
+ }
+
+ // Unique
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a unique view of the given iterable.
+ *
+ * The returned iterable's iterator does not supports {@code remove()}.
+ *
+ * @param the element type
+ * @param iterable the iterable to transform, may be null
+ * @return a unique view of the specified iterable
+ */
+ public static Iterable uniqueIterable(final Iterable iterable) {
+ return new AbstractIterable() {
+ @Override
+ public Iterator iterator() {
+ return new UniqueFilterIterator(emptyIteratorIfNull(iterable));
+ }
+ };
+ }
+
+ // Utility methods
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns an empty iterator if the argument is null
,
+ * or returns {@code iterable.iterator()} otherwise.
+ *
+ * @param the element type
+ * @param iterable the iterable, possibly null
+ * @return an empty collection if the argument is null
+ */
+ public static Iterator emptyIteratorIfNull(final Iterable iterable) {
+ return iterable != null ? iterable.iterator() : IteratorUtils.emptyIterator();
+ }
+
+ /**
+ * Answers true if a predicate is true for every element of an iterable.
+ *
+ * A null
or empty iterable returns true.
+ *
+ * @param the type of object the {@link Iterable} contains
+ * @param input the {@link Iterable} to use, may be null
+ * @param predicate the predicate to use, may not be null
+ * @return true if every element of the collection matches the predicate or if the
+ * collection is empty, false otherwise
+ * @throws NullPointerException if predicate is null
+ */
+ public static boolean matchesAll(final Iterable iterable, final Predicate super E> predicate) {
+ return IteratorUtils.matchesAll(emptyIteratorIfNull(iterable), predicate);
+ }
+
+ /**
+ * Answers true if a predicate is true for any element of the iterable.
+ *
+ * A null
or empty iterable returns false.
+ *
+ * @param the type of object the {@link Iterable} contains
+ * @param input the {@link Iterable} to use, may be null
+ * @param predicate the predicate to use, may not be null
+ * @return true if any element of the collection matches the predicate, false otherwise
+ * @throws NullPointerException if predicate is null
+ */
+ public static boolean matchesAny(final Iterable iterable, final Predicate super E> predicate) {
+ return IteratorUtils.matchesAny(emptyIteratorIfNull(iterable), predicate);
+ }
+
+ /**
+ * Answers true if the provided iterable is empty.
+ *
+ * A null
iterable returns true.
+ *
+ * @param iterable the {@link Iterable to use}, may be null
+ * @return true if the iterable is null or empty, false otherwise
+ */
+ public static boolean isEmpty(final Iterable> iterable) {
+ if (iterable instanceof Collection>) {
+ return ((Collection>) iterable).isEmpty();
+ } else {
+ return IteratorUtils.isEmpty(emptyIteratorIfNull(iterable));
+ }
+ }
+
+ /**
+ * Checks if the object is contained in the given iterable.
+ *
+ * A null
or empty iterable returns false.
+ *
+ * @param the type of object the {@link Iterable} contains
+ * @param iterator the iterable to check, may be null
+ * @param object the object to check
+ * @return true if the object is contained in the iterable, false otherwise
+ */
+ public static boolean contains(final Iterable iterable, final Object object) {
+ if (iterable instanceof Collection>) {
+ return ((Collection) iterable).contains(object);
+ } else {
+ return IteratorUtils.contains(emptyIteratorIfNull(iterable), object);
+ }
+ }
+
+ /**
+ * Returns the index
-th value in the iterable
's {@link Iterator}, throwing
+ * IndexOutOfBoundsException
if there is no such element.
+ *
+ * If the {@link Iterable} is a {@link List}, then it will use {@link List#get(int)}.
+ *
+ * @param the type of object in the {@link Iterable}.
+ * @param iterable the {@link Iterable} to get a value from, may be null
+ * @param index the index to get
+ * @return the object at the specified index
+ * @throws IndexOutOfBoundsException if the index is invalid
+ */
+ public static T get(final Iterable iterable, final int index) {
+ CollectionUtils.checkIndexBounds(index);
+ if (iterable instanceof List>) {
+ return ((List) iterable).get(index);
+ }
+ return IteratorUtils.get(emptyIteratorIfNull(iterable), index);
+ }
+
+ /**
+ * Returns the number of elements contained in the given iterator.
+ *
+ * A null
or empty iterator returns {@code 0}.
+ *
+ * @param iterable the iterable to check, may be null
+ * @return the number of elements contained in the iterable
+ */
+ public static int size(final Iterable> iterable) {
+ if (iterable instanceof Collection>) {
+ return ((Collection>) iterable).size();
+ } else {
+ return IteratorUtils.size(emptyIteratorIfNull(iterable));
+ }
+ }
/**
* Returns a string representation of the elements of the specified iterable.
+ *
* The string representation consists of a list of the iterable's elements,
* enclosed in square brackets ({@code "[]"}). Adjacent elements are separated
* by the characters {@code ", "} (a comma followed by a space). Elements are
* converted to strings as by {@code String.valueOf(Object)}.
*
- * @param the element type
- * @param iterable the iterable to convert to a string
+ * @param the element type
+ * @param iterable the iterable to convert to a string, may be null
* @return a string representation of {@code iterable}
- * @throws IllegalArgumentException if {@code iterable} is null
*/
- public static String toString(Iterable iterable) {
- return toString(iterable, new Transformer() {
- public String transform(C input) {
- return String.valueOf(input);
- }
- }, DEFAULT_TOSTRING_DELIMITER, DEFAULT_TOSTRING_PREFIX, DEFAULT_TOSTRING_SUFFIX);
+ public static String toString(final Iterable iterable) {
+ return IteratorUtils.toString(emptyIteratorIfNull(iterable));
}
/**
* Returns a string representation of the elements of the specified iterable.
+ *
* The string representation consists of a list of the iterable's elements,
* enclosed in square brackets ({@code "[]"}). Adjacent elements are separated
* by the characters {@code ", "} (a comma followed by a space). Elements are
* converted to strings as by using the provided {@code transformer}.
*
- * @param the element type
- * @param iterable the iterable to convert to a string
+ * @param the element type
+ * @param iterable the iterable to convert to a string, may be null
* @param transformer the transformer used to get a string representation of an element
* @return a string representation of {@code iterable}
- * @throws IllegalArgumentException if {@code iterable} or {@code transformer} is null
+ * @throws NullPointerException if {@code transformer} is null
*/
- public static String toString(Iterable iterable, Transformer super C, String> transformer) {
- return toString(iterable, transformer, DEFAULT_TOSTRING_DELIMITER,
- DEFAULT_TOSTRING_PREFIX, DEFAULT_TOSTRING_SUFFIX);
+ public static String toString(final Iterable iterable,
+ final Transformer super E, String> transformer) {
+ if (transformer == null) {
+ throw new NullPointerException("transformer may not be null");
+ }
+ return IteratorUtils.toString(emptyIteratorIfNull(iterable), transformer);
}
/**
* Returns a string representation of the elements of the specified iterable.
+ *
* The string representation consists of a list of the iterable's elements,
* enclosed by the provided {@code prefix} and {@code suffix}. Adjacent elements
* are separated by the provided {@code delimiter}. Elements are converted to
* strings as by using the provided {@code transformer}.
*
- * @param the element type
- * @param iterable the iterable to convert to a string
+ * @param the element type
+ * @param iterable the iterable to convert to a string, may be null
* @param transformer the transformer used to get a string representation of an element
* @param delimiter the string to delimit elements
* @param prefix the prefix, prepended to the string representation
* @param suffix the suffix, appended to the string representation
* @return a string representation of {@code iterable}
- * @throws IllegalArgumentException if any argument is null
+ * @throws NullPointerException if either transformer, delimiter, prefix or suffix is null
*/
- public static String toString(Iterable iterable,
- Transformer super C, String> transformer,
- String delimiter,
- String prefix,
- String suffix) {
- if (iterable == null) {
- throw new IllegalArgumentException("iterable may not be null");
+ public static String toString(final Iterable iterable,
+ final Transformer super E, String> transformer,
+ final String delimiter,
+ final String prefix,
+ final String suffix) {
+ return IteratorUtils.toString(emptyIteratorIfNull(iterable),
+ transformer, delimiter, prefix, suffix);
+ }
+
+ // Inner classes
+ // ----------------------------------------------------------------------
+
+ private static abstract class AbstractIterable implements Iterable {
+ @Override
+ public String toString() {
+ return IterableUtils.toString(this);
}
- if (transformer == null) {
- throw new IllegalArgumentException("transformer may not be null");
- }
- if (delimiter == null) {
- throw new IllegalArgumentException("delimiter may not be null");
- }
- if (prefix == null) {
- throw new IllegalArgumentException("prefix may not be null");
- }
- if (suffix == null) {
- throw new IllegalArgumentException("suffix may not be null");
- }
- final StringBuilder stringBuilder = new StringBuilder(prefix);
- for(final C element : iterable) {
- stringBuilder.append(transformer.transform(element));
- stringBuilder.append(delimiter);
- }
- if(stringBuilder.length() > prefix.length()) {
- stringBuilder.setLength(stringBuilder.length() - delimiter.length());
- }
- stringBuilder.append(suffix);
- return stringBuilder.toString();
}
}
diff --git a/src/main/java/org/apache/commons/collections4/IteratorUtils.java b/src/main/java/org/apache/commons/collections4/IteratorUtils.java
index c240d9d63..15eda1b93 100644
--- a/src/main/java/org/apache/commons/collections4/IteratorUtils.java
+++ b/src/main/java/org/apache/commons/collections4/IteratorUtils.java
@@ -29,6 +29,7 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
+import org.apache.commons.collections4.functors.EqualPredicate;
import org.apache.commons.collections4.iterators.ArrayIterator;
import org.apache.commons.collections4.iterators.ArrayListIterator;
import org.apache.commons.collections4.iterators.BoundedIterator;
@@ -55,6 +56,7 @@ import org.apache.commons.collections4.iterators.PeekingIterator;
import org.apache.commons.collections4.iterators.PushbackIterator;
import org.apache.commons.collections4.iterators.SingletonIterator;
import org.apache.commons.collections4.iterators.SingletonListIterator;
+import org.apache.commons.collections4.iterators.SkippingIterator;
import org.apache.commons.collections4.iterators.TransformIterator;
import org.apache.commons.collections4.iterators.UnmodifiableIterator;
import org.apache.commons.collections4.iterators.UnmodifiableListIterator;
@@ -116,10 +118,26 @@ public class IteratorUtils {
@SuppressWarnings("rawtypes")
public static final OrderedMapIterator EMPTY_ORDERED_MAP_ITERATOR = EmptyOrderedMapIterator.INSTANCE;
+ /**
+ * Default prefix used while converting an Iterator to its String representation.
+ */
+ private static final String DEFAULT_TOSTRING_PREFIX = "[";
+
+ /**
+ * Default suffix used while converting an Iterator to its String representation.
+ */
+ private static final String DEFAULT_TOSTRING_SUFFIX = "]";
+
+ /**
+ * Default delimiter used to delimit elements while converting an Iterator
+ * to its String representation.
+ */
+ private static final String DEFAULT_TOSTRING_DELIMITER = ", ";
+
/**
* IteratorUtils is not normally instantiated.
*/
- private IteratorUtils() {}
+ private IteratorUtils() {}
// Empty
//-----------------------------------------------------------------------
@@ -443,7 +461,7 @@ public class IteratorUtils {
* @param iterator the iterator to decorate
* @param max the maximum number of elements returned by this iterator
* @return a new bounded iterator
- * @throws IllegalArgumentException if the iterator is null or either offset or max is negative
+ * @throws IllegalArgumentException if the iterator is null or max is negative
* @since 4.1
*/
public static BoundedIterator boundedIterator(final Iterator extends E> iterator, long max) {
@@ -471,6 +489,22 @@ public class IteratorUtils {
return new BoundedIterator(iterator, offset, max);
}
+ // Skipping
+ //-----------------------------------------------------------------------
+ /**
+ * Decorates the specified iterator to skip the first N elements.
+ *
+ * @param the element type
+ * @param iterator the iterator to decorate
+ * @param offset the first number of elements to skip
+ * @return a new skipping iterator
+ * @throws IllegalArgumentException if the iterator is null or offset is negative
+ * @since 4.1
+ */
+ public static SkippingIterator skippingIterator(final Iterator iterator, long offset) {
+ return new SkippingIterator(iterator, offset);
+ }
+
// Unmodifiable
//-----------------------------------------------------------------------
/**
@@ -1138,4 +1172,230 @@ public class IteratorUtils {
return singletonIterator(obj);
}
+ // Utility methods
+ //-----------------------------------------------------------------------
+
+ /**
+ * Answers true if a predicate is true for any element of the iterator.
+ *
+ * A null
or empty iterator returns false.
+ *
+ * @param the type of object the {@link Iterator} contains
+ * @param input the {@link Iterator} to use, may be null
+ * @param predicate the predicate to use, may not be null
+ * @return true if any element of the collection matches the predicate, false otherwise
+ * @throws NullPointerException if predicate is null
+ * @since 4.1
+ */
+ public static boolean matchesAny(final Iterator iterator, final Predicate super E> predicate) {
+ if (predicate == null) {
+ throw new NullPointerException("Predicate must not be null");
+ }
+
+ if (iterator != null) {
+ while (iterator.hasNext()) {
+ final E element = iterator.next();
+ if (predicate.evaluate(element)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Answers true if a predicate is true for every element of an iterator.
+ *
+ * A null
or empty iterator returns true.
+ *
+ * @param the type of object the {@link Iterator} contains
+ * @param input the {@link Iterator} to use, may be null
+ * @param predicate the predicate to use, may not be null
+ * @return true if every element of the collection matches the predicate or if the
+ * collection is empty, false otherwise
+ * @throws NullPointerException if predicate is null
+ * @since 4.1
+ */
+ public static boolean matchesAll(final Iterator iterator, final Predicate super E> predicate) {
+ if (predicate == null) {
+ throw new NullPointerException("Predicate must not be null");
+ }
+
+ if (iterator != null) {
+ while (iterator.hasNext()) {
+ final E element = iterator.next();
+ if (!predicate.evaluate(element)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the given iterator is empty.
+ *
+ * A null
or empty iterator returns true.
+ *
+ * @param iterator the {@link Iterator} to use, may be null
+ * @return true if the iterator is exhausted or null, false otherwise
+ * @since 4.1
+ */
+ public static boolean isEmpty(final Iterator> iterator) {
+ return iterator == null || !iterator.hasNext();
+ }
+
+ /**
+ * Checks if the object is contained in the given iterator.
+ *
+ * A null
or empty iterator returns false.
+ *
+ * @param the type of object the {@link Iterator} contains
+ * @param iterator the iterator to check, may be null
+ * @param object the object to check
+ * @return true if the object is contained in the iterator, false otherwise
+ * @since 4.1
+ */
+ public static boolean contains(final Iterator iterator, final Object object) {
+ return matchesAny(iterator, EqualPredicate.equalPredicate(object));
+ }
+
+ /**
+ * Returns the index
-th value in {@link Iterator}, throwing
+ * IndexOutOfBoundsException
if there is no such element.
+ *
+ * The Iterator is advanced to index
(or to the end, if
+ * index
exceeds the number of entries) as a side effect of this method.
+ *
+ * @param the type of object in the {@link Iterator}
+ * @param iterator the iterator to get a value from
+ * @param index the index to get
+ * @return the object at the specified index
+ * @throws IndexOutOfBoundsException if the index is invalid
+ * @throws IllegalArgumentException if the object type is invalid
+ * @since 4.1
+ */
+ public static E get(final Iterator iterator, final int index) {
+ int i = index;
+ CollectionUtils.checkIndexBounds(i);
+ while (iterator.hasNext()) {
+ i--;
+ if (i == -1) {
+ return iterator.next();
+ }
+ iterator.next();
+ }
+ throw new IndexOutOfBoundsException("Entry does not exist: " + i);
+ }
+
+ /**
+ * Returns the number of elements contained in the given iterator.
+ *
+ * A null
or empty iterator returns {@code 0}.
+ *
+ * @param iterator the iterator to check, may be null
+ * @return the number of elements contained in the iterator
+ * @since 4.1
+ */
+ public static int size(final Iterator> iterator) {
+ int size = 0;
+ if (iterator != null) {
+ while (iterator.hasNext()) {
+ iterator.next();
+ size++;
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Returns a string representation of the elements of the specified iterator.
+ *
+ * The string representation consists of a list of the iterator's elements,
+ * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated
+ * by the characters {@code ", "} (a comma followed by a space). Elements are
+ * converted to strings as by {@code String.valueOf(Object)}.
+ *
+ * @param the element type
+ * @param iterable the iterator to convert to a string
+ * @return a string representation of {@code iterator}
+ * @since 4.1
+ */
+ public static String toString(final Iterator iterator) {
+ return toString(iterator, TransformerUtils.stringValueTransformer(),
+ DEFAULT_TOSTRING_DELIMITER, DEFAULT_TOSTRING_PREFIX,
+ DEFAULT_TOSTRING_SUFFIX);
+ }
+
+ /**
+ * Returns a string representation of the elements of the specified iterator.
+ *
+ * The string representation consists of a list of the iterable's elements,
+ * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated
+ * by the characters {@code ", "} (a comma followed by a space). Elements are
+ * converted to strings as by using the provided {@code transformer}.
+ *
+ * @param the element type
+ * @param iterable the iterator to convert to a string, may be null
+ * @param transformer the transformer used to get a string representation of an element
+ * @return a string representation of {@code iterator}
+ * @throws NullPointerException if {@code transformer} is null
+ * @since 4.1
+ */
+ public static String toString(final Iterator iterator,
+ final Transformer super E, String> transformer) {
+ return toString(iterator, transformer, DEFAULT_TOSTRING_DELIMITER,
+ DEFAULT_TOSTRING_PREFIX, DEFAULT_TOSTRING_SUFFIX);
+ }
+
+ /**
+ * Returns a string representation of the elements of the specified iterator.
+ *
+ * The string representation consists of a list of the iterator's elements,
+ * enclosed by the provided {@code prefix} and {@code suffix}. Adjacent elements
+ * are separated by the provided {@code delimiter}. Elements are converted to
+ * strings as by using the provided {@code transformer}.
+ *
+ * @param the element type
+ * @param iterator the iterator to convert to a string, may be null
+ * @param transformer the transformer used to get a string representation of an element
+ * @param delimiter the string to delimit elements
+ * @param prefix the prefix, prepended to the string representation
+ * @param suffix the suffix, appended to the string representation
+ * @return a string representation of {@code iterator}
+ * @throws NullPointerException if either transformer, delimiter, prefix or suffix is null
+ * @since 4.1
+ */
+ public static String toString(final Iterator iterator,
+ final Transformer super E, String> transformer,
+ final String delimiter,
+ final String prefix,
+ final String suffix) {
+ if (transformer == null) {
+ throw new NullPointerException("transformer may not be null");
+ }
+ if (delimiter == null) {
+ throw new NullPointerException("delimiter may not be null");
+ }
+ if (prefix == null) {
+ throw new NullPointerException("prefix may not be null");
+ }
+ if (suffix == null) {
+ throw new NullPointerException("suffix may not be null");
+ }
+ final StringBuilder stringBuilder = new StringBuilder(prefix);
+ if (iterator != null) {
+ while (iterator.hasNext()) {
+ final E element = iterator.next();
+ stringBuilder.append(transformer.transform(element));
+ stringBuilder.append(delimiter);
+ }
+ if(stringBuilder.length() > prefix.length()) {
+ stringBuilder.setLength(stringBuilder.length() - delimiter.length());
+ }
+ }
+ stringBuilder.append(suffix);
+ return stringBuilder.toString();
+ }
+
}
diff --git a/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java b/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java
new file mode 100644
index 000000000..aa0e7bcab
--- /dev/null
+++ b/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
+ * or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+package org.apache.commons.collections4.iterators;
+
+import java.util.Iterator;
+
+/**
+ * Decorates another iterator to skip the first N elements.
+ *
+ * In case an offset parameter other than 0 is provided, the decorated
+ * iterator is immediately advanced to this position, skipping all elements
+ * before that position.
+ *
+ * @since 4.1
+ * @version $Id: $
+ */
+public class SkippingIterator extends AbstractIteratorDecorator {
+
+ /** The offset to bound the first element return */
+ private final long offset;
+
+ /** The position of the current element */
+ private long pos;
+
+ //-----------------------------------------------------------------------
+
+ /**
+ * Decorates the specified iterator to skip all elements until the iterator
+ * reaches the position at {@code offset}.
+ *
+ * The iterator is immediately advanced until it reaches the position at {@code offset},
+ * incurring O(n) time.
+ *
+ * @param iterator the iterator to be decorated
+ * @param offset the index of the first element of the decorated iterator to return
+ * @throws IllegalArgumentException if iterator is null, or offset is negative
+ */
+ public SkippingIterator(final Iterator iterator, final long offset) {
+ super(iterator);
+
+ if (offset < 0) {
+ throw new IllegalArgumentException("Offset parameter must not be negative.");
+ }
+
+ this.offset = offset;
+ this.pos = 0;
+ init();
+ }
+
+ /**
+ * Skips the given number of elements.
+ */
+ private void init() {
+ while (pos < offset && hasNext()) {
+ next();
+ pos++;
+ }
+ }
+
+ //-----------------------------------------------------------------------
+
+ @Override
+ public E next() {
+ final E next = super.next();
+ pos++;
+ return next;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * In case an offset other than 0 was specified, the underlying iterator will be advanced
+ * to this position upon creation. A call to {@link #remove()} will still result in an
+ * {@link IllegalStateException} if no explicit call to {@link #next()} has been made prior
+ * to calling {@link #remove()}.
+ */
+ @Override
+ public void remove() {
+ if (pos <= offset) {
+ throw new IllegalStateException("remove() can not be called before calling next()");
+ }
+ super.remove();
+ }
+
+}
diff --git a/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java b/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java
index 71e812eeb..dd1fa0d0d 100644
--- a/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java
@@ -65,12 +65,8 @@ public class IterableUtilsTest extends BulkTest {
result = IterableUtils.toString(new ArrayList());
assertEquals("[]", result);
- try {
- IterableUtils.toString(null);
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
- // expected
- }
+ result = IterableUtils.toString(null);
+ assertEquals("[]", result);
result = IterableUtils.toString(iterableA, new Transformer() {
public String transform(Integer input) {
@@ -87,17 +83,13 @@ public class IterableUtilsTest extends BulkTest {
});
assertEquals("[]", result);
- try {
- IterableUtils.toString(null, new Transformer() {
- public String transform(Integer input) {
- fail("not supposed to reach here");
- return "";
- }
- });
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
- // expected
- }
+ result = IterableUtils.toString(null, new Transformer() {
+ public String transform(Integer input) {
+ fail("not supposed to reach here");
+ return "";
+ }
+ });
+ assertEquals("[]", result);
}
public void testToStringDelimiter() {
@@ -137,22 +129,18 @@ public class IterableUtilsTest extends BulkTest {
}
public void testToStringWithNullArguments() {
- try {
- IterableUtils.toString(null, new Transformer() {
- public String transform(Integer input) {
- fail("not supposed to reach here");
- return "";
- }
- }, "", "(", ")");
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
- // expected
- }
+ String result = IterableUtils.toString(null, new Transformer() {
+ public String transform(Integer input) {
+ fail("not supposed to reach here");
+ return "";
+ }
+ }, "", "(", ")");
+ assertEquals("()", result);
try {
IterableUtils.toString(new ArrayList(), null, "", "(", ")");
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
+ fail("expecting NullPointerException");
+ } catch (final NullPointerException ex) {
// expected
}
@@ -163,8 +151,8 @@ public class IterableUtilsTest extends BulkTest {
return "";
}
}, null, "(", ")");
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
+ fail("expecting NullPointerException");
+ } catch (final NullPointerException ex) {
// expected
}
@@ -175,8 +163,8 @@ public class IterableUtilsTest extends BulkTest {
return "";
}
}, "", null, ")");
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
+ fail("expecting NullPointerException");
+ } catch (final NullPointerException ex) {
// expected
}
@@ -187,8 +175,8 @@ public class IterableUtilsTest extends BulkTest {
return "";
}
}, "", "(", null);
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
+ fail("expecting NullPointerException");
+ } catch (final NullPointerException ex) {
// expected
}
}