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}