diff --git a/src/main/java/org/apache/commons/collections4/FluentIterable.java b/src/main/java/org/apache/commons/collections4/FluentIterable.java index d3d77f779..91e604592 100644 --- a/src/main/java/org/apache/commons/collections4/FluentIterable.java +++ b/src/main/java/org/apache/commons/collections4/FluentIterable.java @@ -23,19 +23,25 @@ import java.util.Iterator; import java.util.List; /** - * A FluentIterable provides a powerful yet simple API for manipulating Iterable instances in a fluent manner. + * A FluentIterable provides a powerful yet simple API for manipulating + * Iterable instances in a fluent manner. *

- * A FluentIterable can be created either from an Iterable or from a set of elements. - * The following types of methods are provided: + * A FluentIterable can be created either from an Iterable or from a set + * of elements. The following types of methods are provided: *

*

- * The following example outputs the first 3 even numbers in the range [1, 10] into a list: + * The following example outputs the first 3 even numbers in the range [1, 10] + * into a list: *

+ * List<String> result =
  *   FluentIterable
  *       .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  *       .filter(new Predicate() {
@@ -47,6 +53,8 @@ import java.util.List;
  *       .limit(3)
  *       .toList();
  * 
+ * The resulting list will contain the following elements: + *
[2, 4, 6]
* * @param the element type * @since 4.1 @@ -54,16 +62,38 @@ import java.util.List; */ public class FluentIterable implements Iterable { + /** A reference to the wrapped iterable. */ private final Iterable iterable; // Static factory methods // ---------------------------------------------------------------------- - public static FluentIterable of(T... elements) { + /** + * Creates a new FluentIterable from the provided elements. + *

+ * The returned iterable's iterator does not support {@code remove()}. + * + * @param the element type + * @param elements the elements to be contained in the FluentIterable + * @return a new FluentIterable containing the provided elements + */ + public static FluentIterable of(final T... elements) { return of(Arrays.asList(elements)); } - - public static FluentIterable of(Iterable iterable) { + + /** + * Construct a new FluentIterable from the provided iterable. If the + * iterable is already an instance of FluentIterable, the instance + * will be returned instead. + *

+ * The returned iterable's iterator supports {@code remove()} when the + * corresponding input iterator supports it. + * + * @param the element type + * @param iterable the iterable to wrap into a FluentIterable + * @return a new FluentIterable wrapping the provided iterable + */ + public static FluentIterable of(final Iterable iterable) { if (iterable == null) { throw new NullPointerException("Iterable must not be null"); } @@ -77,6 +107,17 @@ public class FluentIterable implements Iterable { // Constructor // ---------------------------------------------------------------------- + /** + * Package-private constructor, used by IterableUtils. + */ + FluentIterable() { + this.iterable = this; + } + + /** + * Create a new FluentIterable by wrapping the provided iterable. + * @param iterable the iterable to wrap + */ private FluentIterable(final Iterable iterable) { this.iterable = iterable; } @@ -84,38 +125,114 @@ public class FluentIterable implements Iterable { // fluent construction methods // ---------------------------------------------------------------------- + /** + * Returns a new FluentIterable whose iterator will first traverse + * the elements of the current iterable, followed by the provided + * elements. + * + * @param elements the elements to append to the iterable + * @return a new iterable, combining this iterable with the elements + */ public FluentIterable append(final E... elements) { return append(Arrays.asList(elements)); } + /** + * Returns a new FluentIterable whose iterator will first traverse + * the elements of the current iterable, followed by the elements + * of the provided iterable. + *

+ * A null iterable will be treated as an empty iterable. + * + * @param other the other iterable to combine, may be null + * @return a new iterable, combining this iterable with other + */ public FluentIterable append(final Iterable other) { return of(IterableUtils.chainedIterable(iterable, other)); } - + + /** + * This method fully traverses an iterator of this iterable and returns + * a new iterable with the same contents, but without any reference + * to the originating iterables and/or iterators. + *

+ * Calling this method is equivalent to: + *

+     *   FluentIterable someIterable = ...;
+     *   FluentIterable.of(someIterable.toList());
+     * 
+ * + * @return a new iterable with the same contents as this iterable + */ public FluentIterable eval() { return of(toList()); } + /** + * Returns a new FluentIterable whose iterator will only return + * elements from this iterable matching the provided predicate. + * + * @param predicate the predicate used to filter elements + * @return a new iterable, providing a filtered view of this iterable + * @throws NullPointerException if predicate is null + */ public FluentIterable filter(final Predicate predicate) { return of(IterableUtils.filteredIterable(iterable, predicate)); } + /** + * Returns a new FluentIterable whose iterator will return at most + * the provided maximum number of elements from this iterable. + * + * @param maxSize the maximum number of elements + * @return a new iterable, providing a bounded view of this iterable + * @throws IllegalArgumentException if maxSize is negative + */ public FluentIterable limit(final int maxSize) { return of(IterableUtils.boundedIterable(iterable, maxSize)); } + /** + * Returns a new FluentIterable whose iterator will loop infinitely + * over the elements from this iterable. + * + * @return a new iterable, providing a looping view of this iterable + */ public FluentIterable loop() { return of(IterableUtils.loopingIterable(iterable)); } + /** + * Returns a new FluentIterable whose iterator will skip the first + * N elements from this iterable. + * + * @param elementsToSkip the number of elements to skip + * @return a new iterable, providing a view of this iterable by skipping + * the first N elements + * @throws IllegalArgumentException if elementsToSkip is negative + */ public FluentIterable skip(int elementsToSkip) { return of(IterableUtils.skippingIterable(iterable, elementsToSkip)); } + /** + * Returns a new FluentIterable whose iterator will return all elements + * of this iterable transformed by the provided transformer. + * + * @param transformer the transformer applied to each element + * @return a new iterable, providing a transformed view of this iterable + * @throws NullPointerException if transformer is null + */ public FluentIterable transform(final Transformer transformer) { return of(IterableUtils.transformedIterable(iterable, transformer)); } + /** + * Returns a new FluentIterable whose iterator will return a unique view + * of this iterable. + * + * @return a new iterable, providing a unique view of this iterable + */ public FluentIterable unique() { return of(IterableUtils.uniqueIterable(iterable)); } @@ -123,38 +240,100 @@ public class FluentIterable implements Iterable { // convenience methods // ---------------------------------------------------------------------- + /** {@inheritDoc} */ public Iterator iterator() { return iterable.iterator(); } + /** + * Returns an Enumeration that will enumerate all elements contained + * in this iterable. + * + * @return an Enumeration over the elements of this iterable + */ public Enumeration asEnumeration() { return IteratorUtils.asEnumeration(iterator()); } + /** + * Checks if all elements contained in this iterable are matching the + * provided predicate. + *

+ * A null or empty iterable returns true. + * + * @param predicate the predicate to use, may not be null + * @return true if all elements contained in this iterable match the predicate, + * false otherwise + * @throws NullPointerException if predicate is null + */ public boolean allMatch(final Predicate predicate) { return IterableUtils.matchesAll(iterable, predicate); } + /** + * Checks if this iterable contains any element matching the provided predicate. + *

+ * A null or empty iterable returns false. + * + * @param predicate the predicate to use, may not be null + * @return true if at least one element contained in this iterable matches the predicate, + * false otherwise + * @throws NullPointerException if predicate is null + */ public boolean anyMatch(final Predicate predicate) { return IterableUtils.matchesAny(iterable, predicate); } + /** + * Checks if this iterable is empty. + * + * @return true if this iterable does not contain any elements, false otherwise + */ public boolean isEmpty() { return IterableUtils.isEmpty(iterable); } + /** + * Checks if the object is contained in this iterable. + * + * @param object the object to check + * @return true if the object is contained in this iterable, false otherwise + */ public boolean contains(final Object object) { return IterableUtils.contains(iterable, object); } - public E get(int position) { + /** + * Returns the element at the provided position in this iterable. + * In order to return the element, an iterator needs to be traversed + * up to the requested position. + * + * @param position the position of the element to return + * @return the element + * @throws IndexOutOfBoundsException if the provided position is outside the + * valid range of this iterable: [0, size) + */ + public E get(final int position) { return IterableUtils.get(iterable, position); } + /** + * Returns the number of elements that are contained in this iterable. + * In order to determine the size, an iterator needs to be traversed. + * + * @return the size of this iterable + */ public int size() { return IterableUtils.size(iterable); } + /** + * Traverses an iterator of this iterable and adds all elements + * to the provided collection. + * + * @param collection the collection to add the elements + * @throws NullPointerException if collection is null + */ public void copyInto(final Collection collection) { if (collection == null) { throw new NullPointerException("Collection must not be null"); @@ -165,14 +344,31 @@ public class FluentIterable implements Iterable { } } + /** + * Returns an array containing all elements of this iterable by traversing + * its iterator. + * + * @param arrayClass the class of array to create + * @return an array of the iterable contents + * @throws ClassCastException if arrayClass is invalid + */ public E[] toArray(final Class arrayClass) { return IteratorUtils.toArray(iterator(), arrayClass); } + /** + * Returns a list containing all elements of this iterable by traversing + * its iterator. + *

+ * The returned list is mutable. + * + * @return a list of the iterable contents + */ public List toList() { return IteratorUtils.toList(iterator()); } + /** {@inheritDoc} */ @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 de5ae84b6..6bccbd64c 100644 --- a/src/main/java/org/apache/commons/collections4/IterableUtils.java +++ b/src/main/java/org/apache/commons/collections4/IterableUtils.java @@ -117,7 +117,7 @@ public class IterableUtils { * @return a new iterable, combining the provided iterables */ public static Iterable chainedIterable(final Iterable... iterables) { - return new AbstractIterable() { + return new FluentIterable() { @Override public Iterator iterator() { return new LazyIteratorChain() { @@ -156,7 +156,7 @@ public class IterableUtils { throw new NullPointerException("predicate must not be null."); } - return new AbstractIterable() { + return new FluentIterable() { @Override public Iterator iterator() { return IteratorUtils.filteredIterator(emptyIteratorIfNull(iterable), predicate); @@ -185,7 +185,7 @@ public class IterableUtils { throw new IllegalArgumentException("maxSize parameter must not be negative."); } - return new AbstractIterable() { + return new FluentIterable() { @Override public Iterator iterator() { return IteratorUtils.boundedIterator(emptyIteratorIfNull(iterable), maxSize); @@ -211,14 +211,14 @@ public class IterableUtils { * @return a view of the iterable, providing an infinite loop over its elements */ public static Iterable loopingIterable(final Iterable iterable) { - return new AbstractIterable() { + return new FluentIterable() { @Override public Iterator iterator() { return new LazyIteratorChain() { @Override protected Iterator nextIterator(int count) { if (iterable != null) { - if (isEmpty(iterable)) { + if (IterableUtils.isEmpty(iterable)) { return null; } else { return iterable.iterator(); @@ -252,7 +252,7 @@ public class IterableUtils { throw new IllegalArgumentException("elementsToSkip parameter must not be negative."); } - return new AbstractIterable() { + return new FluentIterable() { @Override public Iterator iterator() { return IteratorUtils.skippingIterator(emptyIteratorIfNull(iterable), elementsToSkip); @@ -281,7 +281,7 @@ public class IterableUtils { throw new NullPointerException("transformer must not be null."); } - return new AbstractIterable() { + return new FluentIterable() { @Override public Iterator iterator() { return IteratorUtils.transformedIterator(emptyIteratorIfNull(iterable), transformer); @@ -302,7 +302,7 @@ public class IterableUtils { * @return a unique view of the specified iterable */ public static Iterable uniqueIterable(final Iterable iterable) { - return new AbstractIterable() { + return new FluentIterable() { @Override public Iterator iterator() { return new UniqueFilterIterator(emptyIteratorIfNull(iterable)); @@ -490,13 +490,4 @@ public class IterableUtils { transformer, delimiter, prefix, suffix); } - // Inner classes - // ---------------------------------------------------------------------- - - private static abstract class AbstractIterable implements Iterable { - @Override - public String toString() { - return IterableUtils.toString(this); - } - } }