    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.collections4;
    018
    019import java.util.Arrays;
    020import java.util.Collection;
    021import java.util.Comparator;
    022import java.util.Enumeration;
    023import java.util.Iterator;
    024import java.util.List;
    025
    026import org.apache.commons.collections4.iterators.SingletonIterator;
    027
    028/**
    029 * A FluentIterable provides a powerful yet simple API for manipulating
    030 * Iterable instances in a fluent manner.
    031 * <p>
    032 * A FluentIterable can be created either from an Iterable or from a set
    033 * of elements. The following types of methods are provided:
    034 * <ul>
    035 *   <li>fluent methods which return a new {@code FluentIterable} instance,
    036 *       providing a view of the original iterable (e.g. filter(Predicate));
    037 *   <li>conversion methods which copy the FluentIterable's contents into a
    038 *       new collection or array (e.g. toList());
    039 *   <li>utility methods which answer questions about the FluentIterable's
    040 *       contents (e.g. size(), anyMatch(Predicate)).
    041 *   <li>
    042 * </ul>
    043 * <p>
    044 * The following example outputs the first 3 even numbers in the range [1, 10]
    045 * into a list:
    046 * <pre>
    047 * List&lt;String&gt; result =
    048 *   FluentIterable
    049 *       .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    050 *       .filter(new Predicate&lt;Integer&gt;() {
    051 *                   public boolean evaluate(Integer number) {
    052 *                        return number % 2 == 0;
    053 *                   }
    054 *              )
    055 *       .transform(TransformerUtils.stringValueTransformer())
    056 *       .limit(3)
    057 *       .toList();
    058 * </pre>
    059 * The resulting list will contain the following elements:
    060 * <pre>[2, 4, 6]</pre>
    061 *
    062 * @param <E>  the element type
    063 * @since 4.1
    064 */
    065public class FluentIterable<E> implements Iterable<E> {
    066
    067    /** A reference to the wrapped iterable. */
    068    private final Iterable<E> iterable;
    069
    070    // Static factory methods
    071    // ----------------------------------------------------------------------
    072
    073    /**
    074     * Creates a new empty FluentIterable.
    075     *
    076     * @param <T>  the element type
    077     * @return a new empty FluentIterable
    078     */
    079    @SuppressWarnings("unchecked")
    080    public static <T> FluentIterable<T> empty() {
    081        return IterableUtils.EMPTY_ITERABLE;
    082    }
    083
    084    /**
    085     * Creates a new FluentIterable of the single provided element.
    086     * <p>
    087     * The returned iterable's iterator does not support {@code remove()}.
    088     *
    089     * @param <T>  the element type
    090     * @param singleton  the singleton element
    091     * @return a new FluentIterable containing the singleton
    092     */
    093    public static <T> FluentIterable<T> of(final T singleton) {
    094        return of(IteratorUtils.asIterable(new SingletonIterator<>(singleton, false)));
    095    }
    096
    097    /**
    098     * Creates a new FluentIterable from the provided elements.
    099     * <p>
    100     * The returned iterable's iterator does not support {@code remove()}.
    101     *
    102     * @param <T>  the element type
    103     * @param elements  the elements to be contained in the FluentIterable
    104     * @return a new FluentIterable containing the provided elements
    105     */
    106    public static <T> FluentIterable<T> of(final T... elements) {
    107        return of(Arrays.asList(elements));
    108    }
    109
    110    /**
    111     * Construct a new FluentIterable from the provided iterable. If the
    112     * iterable is already an instance of FluentIterable, the instance
    113     * will be returned instead.
    114     * <p>
    115     * The returned iterable's iterator supports {@code remove()} when the
    116     * corresponding input iterator supports it.
    117     *
    118     * @param <T>  the element type
    119     * @param iterable  the iterable to wrap into a FluentIterable, may not be null
    120     * @return a new FluentIterable wrapping the provided iterable
    121     * @throws NullPointerException if iterable is null
    122     */
    123    public static <T> FluentIterable<T> of(final Iterable<T> iterable) {
    124        IterableUtils.checkNotNull(iterable);
    125        if (iterable instanceof FluentIterable<?>) {
    126            return (FluentIterable<T>) iterable;
    127        }
    128        return new FluentIterable<>(iterable);
    129    }
    130
    131    // Constructor
    132    // ----------------------------------------------------------------------
    133
    134    /**
    135     * Package-private constructor, used by IterableUtils.
    136     */
    137    FluentIterable() {
    138        this.iterable = this;
    139    }
    140
    141    /**
    142     * Create a new FluentIterable by wrapping the provided iterable.
    143     * @param iterable  the iterable to wrap
    144     */
    145    private FluentIterable(final Iterable<E> iterable) {
    146        this.iterable = iterable;
    147    }
    148
    149    // fluent construction methods
    150    // ----------------------------------------------------------------------
    151
    152    /**
    153     * Returns a new FluentIterable whose iterator will first traverse
    154     * the elements of the current iterable, followed by the provided
    155     * elements.
    156     *
    157     * @param elements  the elements to append to the iterable
    158     * @return a new iterable, combining this iterable with the elements
    159     */
    160    public FluentIterable<E> append(final E... elements) {
    161        return append(Arrays.asList(elements));
    162    }
    163
    164    /**
    165     * Returns a new FluentIterable whose iterator will first traverse
    166     * the elements of the current iterable, followed by the elements
    167     * of the provided iterable.
    168     *
    169     * @param other  the other iterable to combine, may not be null
    170     * @return a new iterable, combining this iterable with other
    171     * @throws NullPointerException if other is null
    172     */
    173    public FluentIterable<E> append(final Iterable<? extends E> other) {
    174        return of(IterableUtils.chainedIterable(iterable, other));
    175    }
    176
    177    /**
    178     * Returns a new FluentIterable whose iterator will traverse the
    179     * elements of the current and provided iterable in natural order.
    180     * <p>
    181     * Example: natural ordering
    182     * <ul>
    183     *   <li>this contains elements [1, 3, 5, 7]
    184     *   <li>other contains elements [2, 4, 6, 8]
    185     * </ul>
    186     * <p>
    187     * The returned iterable will traverse the elements in the following
    188     * order: [1, 2, 3, 4, 5, 6, 7, 8]
    189     *
    190     * @param other  the other iterable to collate, may not be null
    191     * @return a new iterable, collating this iterable with the other in natural order
    192     * @throws NullPointerException if other is null
    193     * @see org.apache.commons.collections4.iterators.CollatingIterator
    194     */
    195    public FluentIterable<E> collate(final Iterable<? extends E> other) {
    196        return of(IterableUtils.collatedIterable(iterable, other));
    197    }
    198
    199    /**
    200     * Returns a new FluentIterable whose iterator will traverse the
    201     * elements of the current and provided iterable according to the
    202     * ordering defined by an comparator.
    203     * <p>
    204     * Example: descending order
    205     * <ul>
    206     *   <li>this contains elements [7, 5, 3, 1]
    207     *   <li>other contains elements [8, 6, 4, 2]
    208     * </ul>
    209     * <p>
    210     * The returned iterable will traverse the elements in the following
    211     * order: [8, 7, 6, 5, 4, 3, 2, 1]
    212     *
    213     * @param comparator  the comparator to define an ordering, may be null,
    214     *   in which case natural ordering will be used
    215     * @param other  the other iterable to collate, may not be null
    216     * @return a new iterable, collating this iterable with the other in natural order
    217     * @throws NullPointerException if other is null
    218     * @see org.apache.commons.collections4.iterators.CollatingIterator
    219     */
    220    public FluentIterable<E> collate(final Iterable<? extends E> other,
    221                                     final Comparator<? super E> comparator) {
    222        return of(IterableUtils.collatedIterable(comparator, iterable, other));
    223    }
    224
    225    /**
    226     * This method fully traverses an iterator of this iterable and returns
    227     * a new iterable with the same contents, but without any reference
    228     * to the originating iterables and/or iterators.
    229     * <p>
    230     * Calling this method is equivalent to:
    231     * <pre>
    232     *   FluentIterable&lt;E&gt; someIterable = ...;
    233     *   FluentIterable.of(someIterable.toList());
    234     * </pre>
    235     *
    236     * @return a new iterable with the same contents as this iterable
    237     */
    238    public FluentIterable<E> eval() {
    239        return of(toList());
    240    }
    241
    242    /**
    243     * Returns a new FluentIterable whose iterator will only return
    244     * elements from this iterable matching the provided predicate.
    245     *
    246     * @param predicate  the predicate used to filter elements
    247     * @return a new iterable, providing a filtered view of this iterable
    248     * @throws NullPointerException if predicate is null
    249     */
    250    public FluentIterable<E> filter(final Predicate<? super E> predicate) {
    251        return of(IterableUtils.filteredIterable(iterable, predicate));
    252    }
    253
    254    /**
    255     * Returns a new FluentIterable whose iterator will return at most
    256     * the provided maximum number of elements from this iterable.
    257     *
    258     * @param maxSize  the maximum number of elements
    259     * @return a new iterable, providing a bounded view of this iterable
    260     * @throws IllegalArgumentException if maxSize is negative
    261     */
    262    public FluentIterable<E> limit(final long maxSize) {
    263        return of(IterableUtils.boundedIterable(iterable, maxSize));
    264    }
    265
    266    /**
    267     * Returns a new FluentIterable whose iterator will loop infinitely
    268     * over the elements from this iterable.
    269     *
    270     * @return a new iterable, providing a looping view of this iterable
    271     */
    272    public FluentIterable<E> loop() {
    273        return of(IterableUtils.loopingIterable(iterable));
    274    }
    275
    276    /**
    277     * Returns a new FluentIterable whose iterator will traverse the
    278     * elements from this iterable in reverse order.
    279     *
    280     * @return a new iterable, providing a reversed view of this iterable
    281     */
    282    public FluentIterable<E> reverse() {
    283        return of(IterableUtils.reversedIterable(iterable));
    284    }
    285
    286    /**
    287     * Returns a new FluentIterable whose iterator will skip the first
    288     * N elements from this iterable.
    289     *
    290     * @param elementsToSkip  the number of elements to skip
    291     * @return a new iterable, providing a view of this iterable by skipping
    292     *   the first N elements
    293     * @throws IllegalArgumentException if elementsToSkip is negative
    294     */
    295    public FluentIterable<E> skip(final long elementsToSkip) {
    296        return of(IterableUtils.skippingIterable(iterable, elementsToSkip));
    297    }
    298
    299    /**
    300     * Returns a new FluentIterable whose iterator will return all elements
    301     * of this iterable transformed by the provided transformer.
    302     *
    303     * @param <O>  the output element type
    304     * @param transformer  the transformer applied to each element
    305     * @return a new iterable, providing a transformed view of this iterable
    306     * @throws NullPointerException if transformer is null
    307     */
    308    public <O> FluentIterable<O> transform(final Transformer<? super E, ? extends O> transformer) {
    309        return of(IterableUtils.transformedIterable(iterable, transformer));
    310    }
    311
    312    /**
    313     * Returns a new FluentIterable whose iterator will return a unique view
    314     * of this iterable.
    315     *
    316     * @return a new iterable, providing a unique view of this iterable
    317     */
    318    public FluentIterable<E> unique() {
    319        return of(IterableUtils.uniqueIterable(iterable));
    320    }
    321
    322    /**
    323     * Returns a new FluentIterable whose iterator will return an unmodifiable
    324     * view of this iterable.
    325     *
    326     * @return a new iterable, providing an unmodifiable view of this iterable
    327     */
    328    public FluentIterable<E> unmodifiable() {
    329        return of(IterableUtils.unmodifiableIterable(iterable));
    330    }
    331
    332    /**
    333     * Returns a new FluentIterable whose iterator will traverse
    334     * the elements of this iterable and the other iterable in
    335     * alternating order.
    336     *
    337     * @param other  the other iterable to interleave, may not be null
    338     * @return a new iterable, interleaving this iterable with others
    339     * @throws NullPointerException if other is null
    340     */
    341    public FluentIterable<E> zip(final Iterable<? extends E> other) {
    342        return of(IterableUtils.zippingIterable(iterable, other));
    343    }
    344
    345    /**
    346     * Returns a new FluentIterable whose iterator will traverse
    347     * the elements of this iterable and the other iterables in
    348     * alternating order.
    349     *
    350     * @param others  the iterables to interleave, may not be null
    351     * @return a new iterable, interleaving this iterable with others
    352     * @throws NullPointerException if either of the provided iterables is null
    353     */
    354    public FluentIterable<E> zip(final Iterable<? extends E>... others) {
    355        return of(IterableUtils.zippingIterable(iterable, others));
    356    }
    357
    358    // convenience methods
    359    // ----------------------------------------------------------------------
    360
    361    /** {@inheritDoc} */
    362    @Override
    363    public Iterator<E> iterator() {
    364        return iterable.iterator();
    365    }
    366
    367    /**
    368     * Returns an Enumeration that will enumerate all elements contained
    369     * in this iterable.
    370     *
    371     * @return an Enumeration over the elements of this iterable
    372     */
    373    public Enumeration<E> asEnumeration() {
    374        return IteratorUtils.asEnumeration(iterator());
    375    }
    376
    377    /**
    378     * Checks if all elements contained in this iterable are matching the
    379     * provided predicate.
    380     * <p>
    381     * A <code>null</code> or empty iterable returns true.
    382     *
    383     * @param predicate  the predicate to use, may not be null
    384     * @return true if all elements contained in this iterable match the predicate,
    385     *   false otherwise
    386     * @throws NullPointerException if predicate is null
    387     */
    388    public boolean allMatch(final Predicate<? super E> predicate) {
    389        return IterableUtils.matchesAll(iterable, predicate);
    390    }
    391
    392    /**
    393     * Checks if this iterable contains any element matching the provided predicate.
    394     * <p>
    395     * A <code>null</code> or empty iterable returns false.
    396     *
    397     * @param predicate  the predicate to use, may not be null
    398     * @return true if at least one element contained in this iterable matches the predicate,
    399     *   false otherwise
    400     * @throws NullPointerException if predicate is null
    401     */
    402    public boolean anyMatch(final Predicate<? super E> predicate) {
    403        return IterableUtils.matchesAny(iterable, predicate);
    404    }
    405
    406    /**
    407     * Checks if this iterable is empty.
    408     *
    409     * @return true if this iterable does not contain any elements, false otherwise
    410     */
    411    public boolean isEmpty() {
    412        return IterableUtils.isEmpty(iterable);
    413    }
    414
    415    /**
    416     * Checks if the object is contained in this iterable.
    417     *
    418     * @param object  the object to check
    419     * @return true if the object is contained in this iterable, false otherwise
    420     */
    421    public boolean contains(final Object object) {
    422        return IterableUtils.contains(iterable, object);
    423    }
    424
    425    /**
    426     * Applies the closure to all elements contained in this iterable.
    427     *
    428     * @param closure  the closure to apply to each element, may not be null
    429     * @throws NullPointerException if closure is null
    430     */
    431    public void forEach(final Closure<? super E> closure) {
    432        IterableUtils.forEach(iterable, closure);
    433    }
    434
    435    /**
    436     * Returns the element at the provided position in this iterable.
    437     * In order to return the element, an iterator needs to be traversed
    438     * up to the requested position.
    439     *
    440     * @param position  the position of the element to return
    441     * @return the element
    442     * @throws IndexOutOfBoundsException if the provided position is outside the
    443     *   valid range of this iterable: [0, size)
    444     */
    445    public E get(final int position) {
    446        return IterableUtils.get(iterable, position);
    447    }
    448
    449    /**
    450     * Returns the number of elements that are contained in this iterable.
    451     * In order to determine the size, an iterator needs to be traversed.
    452     *
    453     * @return the size of this iterable
    454     */
    455    public int size() {
    456        return IterableUtils.size(iterable);
    457    }
    458
    459    /**
    460     * Traverses an iterator of this iterable and adds all elements
    461     * to the provided collection.
    462     *
    463     * @param collection  the collection to add the elements
    464     * @throws NullPointerException if collection is null
    465     */
    466    public void copyInto(final Collection<? super E> collection) {
    467        if (collection == null) {
    468            throw new NullPointerException("Collection must not be null");
    469        }
    470        CollectionUtils.addAll(collection, iterable);
    471    }
    472
    473    /**
    474     * Returns an array containing all elements of this iterable by traversing
    475     * its iterator.
    476     *
    477     * @param arrayClass  the class of array to create
    478     * @return an array of the iterable contents
    479     * @throws ArrayStoreException if arrayClass is invalid
    480     */
    481    public E[] toArray(final Class<E> arrayClass) {
    482        return IteratorUtils.toArray(iterator(), arrayClass);
    483    }
    484
    485    /**
    486     * Returns a mutable list containing all elements of this iterable
    487     * by traversing its iterator.
    488     * <p>
    489     * The returned list is guaranteed to be mutable.
    490     *
    491     * @return a list of the iterable contents
    492     */
    493    public List<E> toList() {
    494        return IterableUtils.toList(iterable);
    495    }
    496
    497    /** {@inheritDoc} */
    498    @Override
    499    public String toString() {
    500        return IterableUtils.toString(iterable);
    501    }
    502
    503}