You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tn...@apache.org on 2015/05/26 17:54:10 UTC
svn commit: r1681783 - in /commons/proper/collections/trunk/src: changes/
main/java/org/apache/commons/collections4/
main/java/org/apache/commons/collections4/iterators/
test/java/org/apache/commons/collections4/
Author: tn
Date: Tue May 26 15:54:09 2015
New Revision: 1681783
URL: http://svn.apache.org/r1681783
Log:
[COLLECTIONS-464] Add first version of a FluentIterable implementation, cleanup recently toString methods in IterableUtils, add SkippingIterator and additional methods to IteratorUtils and IterableUtils.
Added:
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/FluentIterable.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java
Modified:
commons/proper/collections/trunk/src/changes/changes.xml
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/CollectionUtils.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IterableUtils.java
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java
Modified: commons/proper/collections/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/changes/changes.xml?rev=1681783&r1=1681782&r2=1681783&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/changes/changes.xml (original)
+++ commons/proper/collections/trunk/src/changes/changes.xml Tue May 26 15:54:09 2015
@@ -40,8 +40,8 @@
Added clarification to javadoc of "TreeBag#add(Object)" wrt null arguments.
</action>
<action issue="COLLECTIONS-427" dev="tn" type="add" due-to="Gonçalo Marques">
- Added "toString(...)" methods to newly created "IteratorUtils" class to get a
- string representation of an Iterable instance similar to "Arrays#toString(...)".
+ Added "toString(...)" methods to newly created "IterableUtils" and existing "IteratorUtils"
+ to get a string representation of an Iterable/Iterator instance similar to "Arrays#toString(...)".
</action>
<action issue="COLLECTIONS-427" dev="tn" type="fix">
Reverted performance improvement for "SetUniqueList#retainAll(Collection)"
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/CollectionUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/CollectionUtils.java?rev=1681783&r1=1681782&r2=1681783&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/CollectionUtils.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/CollectionUtils.java Tue May 26 15:54:09 2015
@@ -1384,18 +1384,11 @@ public class CollectionUtils {
* @return the object at the specified index
* @throws IndexOutOfBoundsException if the index is invalid
* @throws IllegalArgumentException if the object type is invalid
+ * @deprecated since 4.1, use {@code IteratorUtils.get(Iterator, int)} instead
*/
+ @Deprecated
public static <T> T get(final Iterator<T> iterator, final int index) {
- int i = index;
- checkIndexBounds(i);
- while (iterator.hasNext()) {
- i--;
- if (i == -1) {
- return iterator.next();
- }
- iterator.next();
- }
- throw new IndexOutOfBoundsException("Entry does not exist: " + i);
+ return IteratorUtils.get(iterator, index);
}
/**
@@ -1432,7 +1425,7 @@ public class CollectionUtils {
* @param index the index to check.
* @throws IndexOutOfBoundsException if the index is negative.
*/
- private static void checkIndexBounds(final int index) {
+ static void checkIndexBounds(final int index) {
if (index < 0) {
throw new IndexOutOfBoundsException("Index cannot be negative: " + index);
}
@@ -1449,13 +1442,11 @@ public class CollectionUtils {
* @param <T> the type of object in the {@link Iterable}.
* @return the object at the specified index
* @throws IndexOutOfBoundsException if the index is invalid
+ * @deprecated since 4.1, use {@code IterableUtils.get(Iterable, int)} instead
*/
+ @Deprecated
public static <T> T get(final Iterable<T> iterable, final int index) {
- checkIndexBounds(index);
- if (iterable instanceof List<?>) {
- return ((List<T>) iterable).get(index);
- }
- return get(iterable.iterator(), index);
+ return IterableUtils.get(iterable, index);
}
/**
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/FluentIterable.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/FluentIterable.java?rev=1681783&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/FluentIterable.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/FluentIterable.java Tue May 26 15:54:09 2015
@@ -0,0 +1,181 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A FluentIterable provides a powerful yet simple API for manipulating Iterable instances in a fluent manner.
+ * <p>
+ * A FluentIterable can be created either from an Iterable or from a set of elements.
+ * The following types of methods are provided:
+ * <ul>
+ * <li>fluent methods which return a new {@code FluentIterable} instance
+ * <li>conversion methods which copy the FluentIterable's contents into a new collection or array (e.g. toList())
+ * <li>utility methods which answer questions about the FluentIterable's contents (e.g. size(), anyMatch(Predicate))
+ * <li>
+ * </ul>
+ * <p>
+ * The following example outputs the first 3 even numbers in the range [1, 10] into a list:
+ * <pre>
+ * FluentIterable
+ * .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ * .filter(new Predicate<Integer>() {
+ * public boolean evaluate(Integer number) {
+ * return number % 2 == 0;
+ * }
+ * )
+ * .transform(TransformerUtils.stringValueTransformer())
+ * .limit(3)
+ * .toList();
+ * </pre>
+ *
+ * @param <E> the element type
+ * @since 4.1
+ * @version $Id: $
+ */
+public class FluentIterable<E> implements Iterable<E> {
+
+ private final Iterable<E> iterable;
+
+ // Static factory methods
+ // ----------------------------------------------------------------------
+
+ public static <T> FluentIterable<T> of(T... elements) {
+ return of(Arrays.asList(elements));
+ }
+
+ public static <T> FluentIterable<T> of(Iterable<T> iterable) {
+ if (iterable == null) {
+ throw new NullPointerException("Iterable must not be null");
+ }
+ if (iterable instanceof FluentIterable<?>) {
+ return (FluentIterable<T>) iterable;
+ } else {
+ return new FluentIterable<T>(iterable);
+ }
+ }
+
+ // Constructor
+ // ----------------------------------------------------------------------
+
+ private FluentIterable(final Iterable<E> iterable) {
+ this.iterable = iterable;
+ }
+
+ // fluent construction methods
+ // ----------------------------------------------------------------------
+
+ public FluentIterable<E> append(final E... elements) {
+ return append(Arrays.asList(elements));
+ }
+
+ public FluentIterable<E> append(final Iterable<E> other) {
+ return of(IterableUtils.chainedIterable(iterable, other));
+ }
+
+ public FluentIterable<E> eval() {
+ return of(toList());
+ }
+
+ public FluentIterable<E> filter(final Predicate<E> predicate) {
+ return of(IterableUtils.filteredIterable(iterable, predicate));
+ }
+
+ public FluentIterable<E> limit(final int maxSize) {
+ return of(IterableUtils.boundedIterable(iterable, maxSize));
+ }
+
+ public FluentIterable<E> loop() {
+ return of(IterableUtils.loopingIterable(iterable));
+ }
+
+ public FluentIterable<E> skip(int elementsToSkip) {
+ return of(IterableUtils.skippingIterable(iterable, elementsToSkip));
+ }
+
+ public <O> FluentIterable<O> transform(final Transformer<? super E, ? extends O> transformer) {
+ return of(IterableUtils.transformedIterable(iterable, transformer));
+ }
+
+ public FluentIterable<E> unique() {
+ return of(IterableUtils.uniqueIterable(iterable));
+ }
+
+ // convenience methods
+ // ----------------------------------------------------------------------
+
+ public Iterator<E> iterator() {
+ return iterable.iterator();
+ }
+
+ public Enumeration<E> asEnumeration() {
+ return IteratorUtils.asEnumeration(iterator());
+ }
+
+ public boolean allMatch(final Predicate<? super E> predicate) {
+ return IterableUtils.matchesAll(iterable, predicate);
+ }
+
+ public boolean anyMatch(final Predicate<? super E> predicate) {
+ return IterableUtils.matchesAny(iterable, predicate);
+ }
+
+ public boolean isEmpty() {
+ return IterableUtils.isEmpty(iterable);
+ }
+
+ public boolean contains(final Object object) {
+ return IterableUtils.contains(iterable, object);
+ }
+
+ public E get(int position) {
+ return IterableUtils.get(iterable, position);
+ }
+
+ public int size() {
+ return IterableUtils.size(iterable);
+ }
+
+ public void copyInto(final Collection<? super E> collection) {
+ if (collection == null) {
+ throw new NullPointerException("Collection must not be null");
+ }
+
+ for (final E element : iterable) {
+ collection.add(element);
+ }
+ }
+
+ public E[] toArray(final Class<E> arrayClass) {
+ return IteratorUtils.toArray(iterator(), arrayClass);
+ }
+
+ public List<E> toList() {
+ return IteratorUtils.toList(iterator());
+ }
+
+ @Override
+ public String toString() {
+ return IterableUtils.toString(iterable);
+ }
+
+}
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IterableUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IterableUtils.java?rev=1681783&r1=1681782&r2=1681783&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IterableUtils.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IterableUtils.java Tue May 26 15:54:09 2015
@@ -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 {
+ // Chained
+ // ----------------------------------------------------------------------
+
+ /**
+ * Combines two iterables into a single iterable.
+ * <p>
+ * 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.
+ * <p>
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param <E> the element type
+ * @param a the first iterable
+ * @param b the second iterable
+ * @return a new iterable, combining the provided iterables
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> Iterable<E> chainedIterable(final Iterable<? extends E> a, final Iterable<? extends E> b) {
+ return chainedIterable(new Iterable[] {a, b});
+ }
+
+ /**
+ * Combines three iterables into a single iterable.
+ * <p>
+ * 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.
+ * <p>
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param <E> 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
+ */
+ @SuppressWarnings("unchecked")
+ public static <E> Iterable<E> 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.
+ * <p>
+ * 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.
+ * <p>
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param <E> 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 <E> Iterable<E> 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.
+ * <p>
+ * 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.
+ * <p>
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param <E> the element type
+ * @param iterables the iterables to combine
+ * @return a new iterable, combining the provided iterables
+ */
+ public static <E> Iterable<E> chainedIterable(final Iterable<? extends E>... iterables) {
+ return new AbstractIterable<E>() {
+ @Override
+ public Iterator<E> iterator() {
+ return new LazyIteratorChain<E>() {
+
+ @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.
+ * <p>
+ * The returned iterable's iterator does not supports {@code remove()}.
+ *
+ * @param <E> 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 <E> Iterable<E> filteredIterable(final Iterable<E> iterable, final Predicate<? super E> predicate) {
+ if (predicate == null) {
+ throw new NullPointerException("predicate must not be null.");
+ }
+
+ return new AbstractIterable<E>() {
+ @Override
+ public Iterator<E> iterator() {
+ return IteratorUtils.filteredIterator(emptyIteratorIfNull(iterable), predicate);
+ }
+ };
+ }
+
+ // Bounded
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a view of the given iterable that contains at most the given number
+ * of elements.
+ * <p>
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param <E> 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 <E> Iterable<E> boundedIterable(final Iterable<E> iterable, final int maxSize) {
+ if (maxSize < 0) {
+ throw new IllegalArgumentException("maxSize parameter must not be negative.");
+ }
+
+ return new AbstractIterable<E>() {
+ @Override
+ public Iterator<E> iterator() {
+ return IteratorUtils.boundedIterator(emptyIteratorIfNull(iterable), maxSize);
+ }
+ };
+ }
+
+ // Looping
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a view of the given iterable which will cycle infinitely over
+ * its elements.
+ * <p>
+ * 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 <E> 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 <E> Iterable<E> loopingIterable(final Iterable<E> iterable) {
+ return new AbstractIterable<E>() {
+ @Override
+ public Iterator<E> iterator() {
+ return new LazyIteratorChain<E>() {
+ @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.
+ * <p>
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param <E> 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 <E> Iterable<E> skippingIterable(final Iterable<E> iterable, final int elementsToSkip) {
+ if (elementsToSkip < 0) {
+ throw new IllegalArgumentException("elementsToSkip parameter must not be negative.");
+ }
+
+ return new AbstractIterable<E>() {
+ @Override
+ public Iterator<E> iterator() {
+ return IteratorUtils.skippingIterator(emptyIteratorIfNull(iterable), elementsToSkip);
+ }
+ };
+ }
+
+ // Transformed
+ // ----------------------------------------------------------------------
+
/**
- * Default prefix used while converting an Iterable to its String representation.
+ * Returns a transformed view of the given iterable where all of its elements
+ * have been transformed by the provided transformer.
+ * <p>
+ * The returned iterable's iterator supports {@code remove()} when the corresponding
+ * input iterator supports it.
+ *
+ * @param <E> 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 <I, O> Iterable<O> transformedIterable(final Iterable<I> iterable, final Transformer<? super I, ? extends O> transformer) {
+ if (transformer == null) {
+ throw new NullPointerException("transformer must not be null.");
+ }
+
+ return new AbstractIterable<O>() {
+ @Override
+ public Iterator<O> iterator() {
+ return IteratorUtils.transformedIterator(emptyIteratorIfNull(iterable), transformer);
+ }
+ };
+ }
+
+ // Unique
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns a unique view of the given iterable.
+ * <p>
+ * The returned iterable's iterator does not supports {@code remove()}.
+ *
+ * @param <E> the element type
+ * @param iterable the iterable to transform, may be null
+ * @return a unique view of the specified iterable
+ */
+ public static <E> Iterable<E> uniqueIterable(final Iterable<E> iterable) {
+ return new AbstractIterable<E>() {
+ @Override
+ public Iterator<E> iterator() {
+ return new UniqueFilterIterator<E>(emptyIteratorIfNull(iterable));
+ }
+ };
+ }
+
+ // Utility methods
+ // ----------------------------------------------------------------------
+
+ /**
+ * Returns an empty iterator if the argument is <code>null</code>,
+ * or returns {@code iterable.iterator()} otherwise.
+ *
+ * @param <E> the element type
+ * @param iterable the iterable, possibly <code>null</code>
+ * @return an empty collection if the argument is <code>null</code>
+ */
+ public static <E> Iterator<E> emptyIteratorIfNull(final Iterable<E> iterable) {
+ return iterable != null ? iterable.iterator() : IteratorUtils.<E>emptyIterator();
+ }
+
+ /**
+ * Answers true if a predicate is true for every element of an iterable.
+ * <p>
+ * A <code>null</code> or empty iterable returns true.
+ *
+ * @param <E> 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 <E> boolean matchesAll(final Iterable<E> 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.
+ * <p>
+ * A <code>null</code> or empty iterable returns false.
+ *
+ * @param <E> 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 <E> boolean matchesAny(final Iterable<E> iterable, final Predicate<? super E> predicate) {
+ return IteratorUtils.matchesAny(emptyIteratorIfNull(iterable), predicate);
+ }
+
+ /**
+ * Answers true if the provided iterable is empty.
+ * <p>
+ * A <code>null</code> iterable returns true.
+ *
+ * @param iterable the {@link Iterable to use}, may be null
+ * @return true if the iterable is null or empty, false otherwise
*/
- private static final String DEFAULT_TOSTRING_PREFIX = "[";
+ public static boolean isEmpty(final Iterable<?> iterable) {
+ if (iterable instanceof Collection<?>) {
+ return ((Collection<?>) iterable).isEmpty();
+ } else {
+ return IteratorUtils.isEmpty(emptyIteratorIfNull(iterable));
+ }
+ }
/**
- * Default suffix used while converting an Iterable to its String representation.
+ * Checks if the object is contained in the given iterable.
+ * <p>
+ * A <code>null</code> or empty iterable returns false.
+ *
+ * @param <E> 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
*/
- private static final String DEFAULT_TOSTRING_SUFFIX = "]";
+ public static <E> boolean contains(final Iterable<E> iterable, final Object object) {
+ if (iterable instanceof Collection<?>) {
+ return ((Collection<E>) iterable).contains(object);
+ } else {
+ return IteratorUtils.contains(emptyIteratorIfNull(iterable), object);
+ }
+ }
/**
- * Default delimiter used to delimit elements while converting an Iterable
- * to its String representation.
+ * Returns the <code>index</code>-th value in the <code>iterable</code>'s {@link Iterator}, throwing
+ * <code>IndexOutOfBoundsException</code> if there is no such element.
+ * <p>
+ * If the {@link Iterable} is a {@link List}, then it will use {@link List#get(int)}.
+ *
+ * @param <T> 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
*/
- private static final String DEFAULT_TOSTRING_DELIMITER = ", ";
+ public static <T> T get(final Iterable<T> iterable, final int index) {
+ CollectionUtils.checkIndexBounds(index);
+ if (iterable instanceof List<?>) {
+ return ((List<T>) iterable).get(index);
+ }
+ return IteratorUtils.get(emptyIteratorIfNull(iterable), index);
+ }
+
+ /**
+ * Returns the number of elements contained in the given iterator.
+ * <p>
+ * A <code>null</code> 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.
+ * <p>
* 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 <C> the element type
- * @param iterable the iterable to convert to a string
+ * @param <E> 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 <C> String toString(Iterable<C> iterable) {
- return toString(iterable, new Transformer<C, String>() {
- public String transform(C input) {
- return String.valueOf(input);
- }
- }, DEFAULT_TOSTRING_DELIMITER, DEFAULT_TOSTRING_PREFIX, DEFAULT_TOSTRING_SUFFIX);
+ public static <E> String toString(final Iterable<E> iterable) {
+ return IteratorUtils.toString(emptyIteratorIfNull(iterable));
}
/**
* Returns a string representation of the elements of the specified iterable.
+ * <p>
* 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 <C> the element type
- * @param iterable the iterable to convert to a string
+ * @param <E> 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 <C> String toString(Iterable<C> iterable, Transformer<? super C, String> transformer) {
- return toString(iterable, transformer, DEFAULT_TOSTRING_DELIMITER,
- DEFAULT_TOSTRING_PREFIX, DEFAULT_TOSTRING_SUFFIX);
+ public static <E> String toString(final Iterable<E> 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.
+ * <p>
* 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 <C> the element type
- * @param iterable the iterable to convert to a string
+ * @param <E> 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 <C> String toString(Iterable<C> iterable,
- Transformer<? super C, String> transformer,
- String delimiter,
- String prefix,
- String suffix) {
- if (iterable == null) {
- throw new IllegalArgumentException("iterable may not be null");
- }
- 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());
+ public static <E> String toString(final Iterable<E> 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<E> implements Iterable<E> {
+ @Override
+ public String toString() {
+ return IterableUtils.toString(this);
}
- stringBuilder.append(suffix);
- return stringBuilder.toString();
}
}
Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java?rev=1681783&r1=1681782&r2=1681783&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/IteratorUtils.java Tue May 26 15:54:09 2015
@@ -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.i
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;
@@ -117,9 +119,25 @@ public class IteratorUtils {
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 <E> BoundedIterator<E> boundedIterator(final Iterator<? extends E> iterator, long max) {
@@ -471,6 +489,22 @@ public class IteratorUtils {
return new BoundedIterator<E>(iterator, offset, max);
}
+ // Skipping
+ //-----------------------------------------------------------------------
+ /**
+ * Decorates the specified iterator to skip the first N elements.
+ *
+ * @param <E> 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 <E> SkippingIterator<E> skippingIterator(final Iterator<E> iterator, long offset) {
+ return new SkippingIterator<E>(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.
+ * <p>
+ * A <code>null</code> or empty iterator returns false.
+ *
+ * @param <E> 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 <E> boolean matchesAny(final Iterator<E> 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.
+ * <p>
+ * A <code>null</code> or empty iterator returns true.
+ *
+ * @param <E> 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 <E> boolean matchesAll(final Iterator<E> 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.
+ * <p>
+ * A <code>null</code> 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.
+ * <p>
+ * A <code>null</code> or empty iterator returns false.
+ *
+ * @param <E> 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 <E> boolean contains(final Iterator<E> iterator, final Object object) {
+ return matchesAny(iterator, EqualPredicate.equalPredicate(object));
+ }
+
+ /**
+ * Returns the <code>index</code>-th value in {@link Iterator}, throwing
+ * <code>IndexOutOfBoundsException</code> if there is no such element.
+ * <p>
+ * The Iterator is advanced to <code>index</code> (or to the end, if
+ * <code>index</code> exceeds the number of entries) as a side effect of this method.
+ *
+ * @param <E> 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> E get(final Iterator<E> 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.
+ * <p>
+ * A <code>null</code> 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.
+ * <p>
+ * 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 <E> the element type
+ * @param iterable the iterator to convert to a string
+ * @return a string representation of {@code iterator}
+ * @since 4.1
+ */
+ public static <E> String toString(final Iterator<E> 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.
+ * <p>
+ * 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 <E> 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 <E> String toString(final Iterator<E> 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.
+ * <p>
+ * 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 <E> 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 <E> String toString(final Iterator<E> 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();
+ }
+
}
Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java?rev=1681783&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections4/iterators/SkippingIterator.java Tue May 26 15:54:09 2015
@@ -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.
+ * <p>
+ * 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<E> extends AbstractIteratorDecorator<E> {
+
+ /** 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}.
+ * <p>
+ * 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<E> 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}
+ * <p>
+ * 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();
+ }
+
+}
Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java?rev=1681783&r1=1681782&r2=1681783&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java (original)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections4/IterableUtilsTest.java Tue May 26 15:54:09 2015
@@ -65,12 +65,8 @@ public class IterableUtilsTest extends B
result = IterableUtils.toString(new ArrayList<Integer>());
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<Integer, String>() {
public String transform(Integer input) {
@@ -87,17 +83,13 @@ public class IterableUtilsTest extends B
});
assertEquals("[]", result);
- try {
- IterableUtils.toString(null, new Transformer<Integer, String>() {
- 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<Integer, String>() {
+ 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 B
}
public void testToStringWithNullArguments() {
- try {
- IterableUtils.toString(null, new Transformer<Integer, String>() {
- 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<Integer, String>() {
+ public String transform(Integer input) {
+ fail("not supposed to reach here");
+ return "";
+ }
+ }, "", "(", ")");
+ assertEquals("()", result);
try {
IterableUtils.toString(new ArrayList<Integer>(), null, "", "(", ")");
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
+ fail("expecting NullPointerException");
+ } catch (final NullPointerException ex) {
// expected
}
@@ -163,8 +151,8 @@ public class IterableUtilsTest extends B
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 B
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 B
return "";
}
}, "", "(", null);
- fail("expecting IllegalArgumentException");
- } catch (final IllegalArgumentException iae) {
+ fail("expecting NullPointerException");
+ } catch (final NullPointerException ex) {
// expected
}
}