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.lang.reflect.Array;
020import java.lang.reflect.Method;
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.Comparator;
024import java.util.Dictionary;
025import java.util.Enumeration;
026import java.util.Iterator;
027import java.util.List;
028import java.util.ListIterator;
029import java.util.Map;
030import java.util.Objects;
031
032import org.apache.commons.collections4.functors.EqualPredicate;
033import org.apache.commons.collections4.iterators.ArrayIterator;
034import org.apache.commons.collections4.iterators.ArrayListIterator;
035import org.apache.commons.collections4.iterators.BoundedIterator;
036import org.apache.commons.collections4.iterators.CollatingIterator;
037import org.apache.commons.collections4.iterators.EmptyIterator;
038import org.apache.commons.collections4.iterators.EmptyListIterator;
039import org.apache.commons.collections4.iterators.EmptyMapIterator;
040import org.apache.commons.collections4.iterators.EmptyOrderedIterator;
041import org.apache.commons.collections4.iterators.EmptyOrderedMapIterator;
042import org.apache.commons.collections4.iterators.EnumerationIterator;
043import org.apache.commons.collections4.iterators.FilterIterator;
044import org.apache.commons.collections4.iterators.FilterListIterator;
045import org.apache.commons.collections4.iterators.IteratorChain;
046import org.apache.commons.collections4.iterators.IteratorEnumeration;
047import org.apache.commons.collections4.iterators.IteratorIterable;
048import org.apache.commons.collections4.iterators.ListIteratorWrapper;
049import org.apache.commons.collections4.iterators.LoopingIterator;
050import org.apache.commons.collections4.iterators.LoopingListIterator;
051import org.apache.commons.collections4.iterators.NodeListIterator;
052import org.apache.commons.collections4.iterators.ObjectArrayIterator;
053import org.apache.commons.collections4.iterators.ObjectArrayListIterator;
054import org.apache.commons.collections4.iterators.ObjectGraphIterator;
055import org.apache.commons.collections4.iterators.PeekingIterator;
056import org.apache.commons.collections4.iterators.PushbackIterator;
057import org.apache.commons.collections4.iterators.SingletonIterator;
058import org.apache.commons.collections4.iterators.SingletonListIterator;
059import org.apache.commons.collections4.iterators.SkippingIterator;
060import org.apache.commons.collections4.iterators.TransformIterator;
061import org.apache.commons.collections4.iterators.UnmodifiableIterator;
062import org.apache.commons.collections4.iterators.UnmodifiableListIterator;
063import org.apache.commons.collections4.iterators.UnmodifiableMapIterator;
064import org.apache.commons.collections4.iterators.ZippingIterator;
065import org.w3c.dom.Node;
066import org.w3c.dom.NodeList;
067
068/**
069 * Provides static utility methods and decorators for {@link Iterator}
070 * instances. The implementations are provided in the iterators subpackage.
071 *
072 * @since 2.1
073 */
074public class IteratorUtils {
075    // validation is done in this class in certain cases because the
076    // public classes allow invalid states
077
078    /**
079     * An iterator over no elements.
080     */
081    @SuppressWarnings("rawtypes")
082    public static final ResettableIterator EMPTY_ITERATOR = EmptyIterator.RESETTABLE_INSTANCE;
083
084    /**
085     * A list iterator over no elements.
086     */
087    @SuppressWarnings("rawtypes")
088    public static final ResettableListIterator EMPTY_LIST_ITERATOR = EmptyListIterator.RESETTABLE_INSTANCE;
089
090    /**
091     * An ordered iterator over no elements.
092     */
093    @SuppressWarnings("rawtypes")
094    public static final OrderedIterator EMPTY_ORDERED_ITERATOR = EmptyOrderedIterator.INSTANCE;
095
096    /**
097     * A map iterator over no elements.
098     */
099    @SuppressWarnings("rawtypes")
100    public static final MapIterator EMPTY_MAP_ITERATOR = EmptyMapIterator.INSTANCE;
101
102    /**
103     * An ordered map iterator over no elements.
104     */
105    @SuppressWarnings("rawtypes")
106    public static final OrderedMapIterator EMPTY_ORDERED_MAP_ITERATOR = EmptyOrderedMapIterator.INSTANCE;
107    /**
108     * Default delimiter used to delimit elements while converting an Iterator
109     * to its String representation.
110     */
111    private static final String DEFAULT_TOSTRING_DELIMITER = ", ";
112
113    // Arrays
114    /**
115     * Gets an iterator over an object array.
116     *
117     * @param <E> the element type
118     * @param array  the array over which to iterate
119     * @return an iterator over the array
120     * @throws NullPointerException if array is null
121     */
122    public static <E> ResettableIterator<E> arrayIterator(final E... array) {
123        return new ObjectArrayIterator<>(array);
124    }
125
126    /**
127     * Gets an iterator over the end part of an object array.
128     *
129     * @param <E> the element type
130     * @param array  the array over which to iterate
131     * @param start  the index to start iterating at
132     * @return an iterator over part of the array
133     * @throws IndexOutOfBoundsException if start is less than zero or greater
134     *   than the length of the array
135     * @throws NullPointerException if array is null
136     */
137    public static <E> ResettableIterator<E> arrayIterator(final E[] array, final int start) {
138        return new ObjectArrayIterator<>(array, start);
139    }
140
141    /**
142     * Gets an iterator over part of an object array.
143     *
144     * @param <E> the element type
145     * @param array  the array over which to iterate
146     * @param start  the index to start iterating at
147     * @param end  the index to finish iterating at
148     * @return an iterator over part of the array
149     * @throws IndexOutOfBoundsException if array bounds are invalid
150     * @throws IllegalArgumentException if end is before start
151     * @throws NullPointerException if array is null
152     */
153    public static <E> ResettableIterator<E> arrayIterator(final E[] array, final int start, final int end) {
154        return new ObjectArrayIterator<>(array, start, end);
155    }
156
157    /**
158     * Gets an iterator over an object or primitive array.
159     * <p>
160     * This method will handle primitive arrays as well as object arrays.
161     * The primitives will be wrapped in the appropriate wrapper class.
162     *
163     * @param <E> the element type
164     * @param array  the array over which to iterate
165     * @return an iterator over the array
166     * @throws IllegalArgumentException if the array is not an array
167     * @throws NullPointerException if array is null
168     */
169    public static <E> ResettableIterator<E> arrayIterator(final Object array) {
170        return new ArrayIterator<>(array);
171    }
172
173    /**
174     * Gets an iterator over the end part of an object or primitive array.
175     * <p>
176     * This method will handle primitive arrays as well as object arrays.
177     * The primitives will be wrapped in the appropriate wrapper class.
178     *
179     * @param <E> the element type
180     * @param array  the array over which to iterate
181     * @param start  the index to start iterating at
182     * @return an iterator over part of the array
183     * @throws IllegalArgumentException if the array is not an array
184     * @throws IndexOutOfBoundsException if start is less than zero or greater
185     *   than the length of the array
186     * @throws NullPointerException if array is null
187     */
188    public static <E> ResettableIterator<E> arrayIterator(final Object array, final int start) {
189        return new ArrayIterator<>(array, start);
190    }
191
192    /**
193     * Gets an iterator over part of an object or primitive array.
194     * <p>
195     * This method will handle primitive arrays as well as object arrays.
196     * The primitives will be wrapped in the appropriate wrapper class.
197     *
198     * @param <E> the element type
199     * @param array  the array over which to iterate
200     * @param start  the index to start iterating at
201     * @param end  the index to finish iterating at
202     * @return an iterator over part of the array
203     * @throws IllegalArgumentException if the array is not an array or end is before start
204     * @throws IndexOutOfBoundsException if array bounds are invalid
205     * @throws NullPointerException if array is null
206     */
207    public static <E> ResettableIterator<E> arrayIterator(final Object array, final int start, final int end) {
208        return new ArrayIterator<>(array, start, end);
209    }
210
211    /**
212     * Gets a list iterator over an object array.
213     *
214     * @param <E> the element type
215     * @param array  the array over which to iterate
216     * @return a list iterator over the array
217     * @throws NullPointerException if array is null
218     */
219    public static <E> ResettableListIterator<E> arrayListIterator(final E... array) {
220        return new ObjectArrayListIterator<>(array);
221    }
222
223    /**
224     * Gets a list iterator over the end part of an object array.
225     *
226     * @param <E> the element type
227     * @param array  the array over which to iterate
228     * @param start  the index to start iterating at
229     * @return a list iterator over part of the array
230     * @throws IndexOutOfBoundsException if start is less than zero
231     * @throws NullPointerException if array is null
232     */
233    public static <E> ResettableListIterator<E> arrayListIterator(final E[] array, final int start) {
234        return new ObjectArrayListIterator<>(array, start);
235    }
236
237    /**
238     * Gets a list iterator over part of an object array.
239     *
240     * @param <E> the element type
241     * @param array  the array over which to iterate
242     * @param start  the index to start iterating at
243     * @param end  the index to finish iterating at
244     * @return a list iterator over part of the array
245     * @throws IndexOutOfBoundsException if array bounds are invalid
246     * @throws IllegalArgumentException if end is before start
247     * @throws NullPointerException if array is null
248     */
249    public static <E> ResettableListIterator<E> arrayListIterator(final E[] array, final int start, final int end) {
250        return new ObjectArrayListIterator<>(array, start, end);
251    }
252
253    /**
254     * Gets a list iterator over an object or primitive array.
255     * <p>
256     * This method will handle primitive arrays as well as object arrays.
257     * The primitives will be wrapped in the appropriate wrapper class.
258     *
259     * @param <E> the element type
260     * @param array  the array over which to iterate
261     * @return a list iterator over the array
262     * @throws IllegalArgumentException if the array is not an array
263     * @throws NullPointerException if array is null
264     */
265    public static <E> ResettableListIterator<E> arrayListIterator(final Object array) {
266        return new ArrayListIterator<>(array);
267    }
268
269    /**
270     * Gets a list iterator over the end part of an object or primitive array.
271     * <p>
272     * This method will handle primitive arrays as well as object arrays.
273     * The primitives will be wrapped in the appropriate wrapper class.
274     *
275     * @param <E> the element type
276     * @param array  the array over which to iterate
277     * @param start  the index to start iterating at
278     * @return a list iterator over part of the array
279     * @throws IllegalArgumentException if the array is not an array
280     * @throws IndexOutOfBoundsException if start is less than zero
281     * @throws NullPointerException if array is null
282     */
283    public static <E> ResettableListIterator<E> arrayListIterator(final Object array, final int start) {
284        return new ArrayListIterator<>(array, start);
285    }
286
287    /**
288     * Gets a list iterator over part of an object or primitive array.
289     * <p>
290     * This method will handle primitive arrays as well as object arrays.
291     * The primitives will be wrapped in the appropriate wrapper class.
292     *
293     * @param <E> the element type
294     * @param array  the array over which to iterate
295     * @param start  the index to start iterating at
296     * @param end  the index to finish iterating at
297     * @return a list iterator over part of the array
298     * @throws IllegalArgumentException if the array is not an array or end is before start
299     * @throws IndexOutOfBoundsException if array bounds are invalid
300     * @throws NullPointerException if array is null
301     */
302    public static <E> ResettableListIterator<E> arrayListIterator(final Object array, final int start, final int end) {
303        return new ArrayListIterator<>(array, start, end);
304    }
305
306    /**
307     * Gets an enumeration that wraps an iterator.
308     *
309     * @param <E> the element type
310     * @param iterator  the iterator to use, may not be null
311     * @return a new enumeration
312     * @throws NullPointerException if iterator is null
313     */
314    public static <E> Enumeration<E> asEnumeration(final Iterator<? extends E> iterator) {
315        return new IteratorEnumeration<>(Objects.requireNonNull(iterator, "iterator"));
316    }
317
318    /**
319     * Gets an {@link Iterable} that wraps an iterator.  The returned {@link Iterable} can be
320     * used for a single iteration.
321     *
322     * @param <E> the element type
323     * @param iterator  the iterator to use, may not be null
324     * @return a new, single use {@link Iterable}
325     * @throws NullPointerException if iterator is null
326     */
327    public static <E> Iterable<E> asIterable(final Iterator<? extends E> iterator) {
328        Objects.requireNonNull(iterator, "iterator");
329        return new IteratorIterable<>(iterator, false);
330    }
331
332    // Views
333    /**
334     * Gets an iterator that provides an iterator view of the given enumeration.
335     *
336     * @param <E> the element type
337     * @param enumeration  the enumeration to use, may not be null
338     * @return a new iterator
339     * @throws NullPointerException if enumeration is null
340     */
341    public static <E> Iterator<E> asIterator(final Enumeration<? extends E> enumeration) {
342        return new EnumerationIterator<>(Objects.requireNonNull(enumeration, "enumeration"));
343    }
344
345    /**
346     * Gets an iterator that provides an iterator view of the given enumeration
347     * that will remove elements from the specified collection.
348     *
349     * @param <E> the element type
350     * @param enumeration  the enumeration to use, may not be null
351     * @param removeCollection  the collection to remove elements from, may not be null
352     * @return a new iterator
353     * @throws NullPointerException if enumeration or removeCollection is null
354     */
355    public static <E> Iterator<E> asIterator(final Enumeration<? extends E> enumeration,
356                                             final Collection<? super E> removeCollection) {
357        return new EnumerationIterator<>(Objects.requireNonNull(enumeration, "enumeration"),
358                Objects.requireNonNull(removeCollection, "removeCollection"));
359    }
360
361    /**
362     * Gets an iterable that wraps an iterator.  The returned iterable can be
363     * used for multiple iterations.
364     *
365     * @param <E> the element type
366     * @param iterator  the iterator to use, may not be null
367     * @return a new, multiple use iterable
368     * @throws NullPointerException if iterator is null
369     */
370    public static <E> Iterable<E> asMultipleUseIterable(final Iterator<? extends E> iterator) {
371        Objects.requireNonNull(iterator, "iterator");
372        return new IteratorIterable<>(iterator, true);
373    }
374
375    // Bounded
376    /**
377     * Decorates the specified iterator to return at most the given number
378     * of elements.
379     *
380     * @param <E> the element type
381     * @param iterator  the iterator to decorate
382     * @param max  the maximum number of elements returned by this iterator
383     * @return a new bounded iterator
384     * @throws NullPointerException if the iterator is null
385     * @throws IllegalArgumentException if max is negative
386     * @since 4.1
387     */
388    public static <E> BoundedIterator<E> boundedIterator(final Iterator<? extends E> iterator, final long max) {
389        return boundedIterator(iterator, 0, max);
390    }
391
392    /**
393     * Decorates the specified iterator to return at most the given number
394     * of elements, skipping all elements until the iterator reaches the
395     * position at {@code offset}.
396     * <p>
397     * The iterator is immediately advanced until it reaches the position at
398     * {@code offset}, incurring O(n) time.
399     *
400     * @param <E> the element type
401     * @param iterator  the iterator to decorate
402     * @param offset  the index of the first element of the decorated iterator to return
403     * @param max  the maximum number of elements returned by this iterator
404     * @return a new bounded iterator
405     * @throws NullPointerException if the iterator is null
406     * @throws IllegalArgumentException if either offset or max is negative
407     * @since 4.1
408     */
409    public static <E> BoundedIterator<E> boundedIterator(final Iterator<? extends E> iterator,
410                                                         final long offset, final long max) {
411        return new BoundedIterator<>(iterator, offset, max);
412    }
413
414    /**
415     * Gets an iterator that iterates through a collections of {@link Iterator}s
416     * one after another.
417     *
418     * @param <E> the element type
419     * @param iterators  the iterators to use, not null or empty or contain nulls
420     * @return a combination iterator over the iterators
421     * @throws NullPointerException if iterators collection is null or contains a null
422     * @throws ClassCastException if the iterators collection contains the wrong object type
423     */
424    public static <E> Iterator<E> chainedIterator(final Collection<Iterator<? extends E>> iterators) {
425        return new IteratorChain<>(iterators);
426    }
427
428    /**
429     * Gets an iterator that iterates through an array of {@link Iterator}s
430     * one after another.
431     *
432     * @param <E> the element type
433     * @param iterators  the iterators to use, not null or empty or contain nulls
434     * @return a combination iterator over the iterators
435     * @throws NullPointerException if iterators array is null or contains a null
436     */
437    public static <E> Iterator<E> chainedIterator(final Iterator<? extends E>... iterators) {
438        return new IteratorChain<>(iterators);
439    }
440
441    /**
442     * Gets an iterator that iterates through two {@link Iterator}s
443     * one after another.
444     *
445     * @param <E> the element type
446     * @param iterator1  the first iterator to use, not null
447     * @param iterator2  the second iterator to use, not null
448     * @return a combination iterator over the iterators
449     * @throws NullPointerException if either iterator is null
450     */
451    public static <E> Iterator<E> chainedIterator(final Iterator<? extends E> iterator1,
452                                                  final Iterator<? extends E> iterator2) {
453        // keep a version with two iterators to avoid the following warning in client code (Java 5 & 6)
454        // "A generic array of E is created for a varargs parameter"
455        return new IteratorChain<>(iterator1, iterator2);
456    }
457
458    /**
459     * Gets an iterator that provides an ordered iteration over the elements
460     * contained in a collection of {@link Iterator}s.
461     * <p>
462     * Given two ordered {@link Iterator}s {@code A} and {@code B},
463     * the {@link Iterator#next()} method will return the lesser of
464     * {@code A.next()} and {@code B.next()} and so on.
465     * <p>
466     * The comparator is optional. If null is specified then natural order is used.
467     *
468     * @param <E> the element type
469     * @param comparator  the comparator to use, may be null for natural order
470     * @param iterators  the iterators to use, not null or empty or contain nulls
471     * @return a combination iterator over the iterators
472     * @throws NullPointerException if iterators collection is null or contains a null
473     * @throws ClassCastException if the iterators collection contains the wrong object type
474     */
475    public static <E> Iterator<E> collatedIterator(final Comparator<? super E> comparator,
476                                                   final Collection<Iterator<? extends E>> iterators) {
477        @SuppressWarnings("unchecked")
478        final Comparator<E> comp =
479            comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : (Comparator<E>) comparator;
480        return new CollatingIterator<>(comp, iterators);
481    }
482
483    /**
484     * Gets an iterator that provides an ordered iteration over the elements
485     * contained in an array of {@link Iterator}s.
486     * <p>
487     * Given two ordered {@link Iterator}s {@code A} and {@code B},
488     * the {@link Iterator#next()} method will return the lesser of
489     * {@code A.next()} and {@code B.next()} and so on.
490     * <p>
491     * The comparator is optional. If null is specified then natural order is used.
492     *
493     * @param <E> the element type
494     * @param comparator  the comparator to use, may be null for natural order
495     * @param iterators  the iterators to use, not null or empty or contain nulls
496     * @return a combination iterator over the iterators
497     * @throws NullPointerException if iterators array is null or contains a null value
498     */
499    public static <E> Iterator<E> collatedIterator(final Comparator<? super E> comparator,
500                                                   final Iterator<? extends E>... iterators) {
501        @SuppressWarnings("unchecked")
502        final Comparator<E> comp =
503            comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : (Comparator<E>) comparator;
504        return new CollatingIterator<>(comp, iterators);
505    }
506
507    // Collated
508    /**
509     * Gets an iterator that provides an ordered iteration over the elements
510     * contained in a collection of ordered {@link Iterator}s.
511     * <p>
512     * Given two ordered {@link Iterator}s {@code A} and {@code B},
513     * the {@link Iterator#next()} method will return the lesser of
514     * {@code A.next()} and {@code B.next()}.
515     * <p>
516     * The comparator is optional. If null is specified then natural order is used.
517     *
518     * @param <E> the element type
519     * @param comparator  the comparator to use, may be null for natural order
520     * @param iterator1  the first iterators to use, not null
521     * @param iterator2  the first iterators to use, not null
522     * @return a combination iterator over the iterators
523     * @throws NullPointerException if either iterator is null
524     */
525    public static <E> Iterator<E> collatedIterator(final Comparator<? super E> comparator,
526                                                   final Iterator<? extends E> iterator1,
527                                                   final Iterator<? extends E> iterator2) {
528        @SuppressWarnings("unchecked")
529        final Comparator<E> comp =
530            comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : (Comparator<E>) comparator;
531        return new CollatingIterator<>(comp, iterator1, iterator2);
532    }
533
534    // Chained
535
536    /**
537     * Checks if the object is contained in the given iterator.
538     * <p>
539     * A {@code null} or empty iterator returns false.
540     *
541     * @param <E> the type of object the {@link Iterator} contains
542     * @param iterator  the iterator to check, may be null
543     * @param object  the object to check
544     * @return true if the object is contained in the iterator, false otherwise
545     * @since 4.1
546     */
547    public static <E> boolean contains(final Iterator<E> iterator, final Object object) {
548        return matchesAny(iterator, EqualPredicate.equalPredicate(object));
549    }
550
551    // Empty
552    /**
553     * Gets an empty iterator.
554     * <p>
555     * This iterator is a valid iterator object that will iterate over nothing.
556     *
557     * @param <E> the element type
558     * @return an iterator over nothing
559     */
560    public static <E> ResettableIterator<E> emptyIterator() {
561        return EmptyIterator.<E>resettableEmptyIterator();
562    }
563
564    /**
565     * Gets an empty list iterator.
566     * <p>
567     * This iterator is a valid list iterator object that will iterate
568     * over nothing.
569     *
570     * @param <E> the element type
571     * @return a list iterator over nothing
572     */
573    public static <E> ResettableListIterator<E> emptyListIterator() {
574        return EmptyListIterator.<E>resettableEmptyListIterator();
575    }
576
577    /**
578     * Gets an empty map iterator.
579     * <p>
580     * This iterator is a valid map iterator object that will iterate
581     * over nothing.
582     *
583     * @param <K> the key type
584     * @param <V> the value type
585     * @return a map iterator over nothing
586     */
587    public static <K, V> MapIterator<K, V> emptyMapIterator() {
588        return EmptyMapIterator.<K, V>emptyMapIterator();
589    }
590
591    /**
592     * Gets an empty ordered iterator.
593     * <p>
594     * This iterator is a valid iterator object that will iterate
595     * over nothing.
596     *
597     * @param <E> the element type
598     * @return an ordered iterator over nothing
599     */
600    public static <E> OrderedIterator<E> emptyOrderedIterator() {
601        return EmptyOrderedIterator.<E>emptyOrderedIterator();
602    }
603
604    /**
605     * Gets an empty ordered map iterator.
606     * <p>
607     * This iterator is a valid map iterator object that will iterate
608     * over nothing.
609     *
610     * @param <K> the key type
611     * @param <V> the value type
612     * @return a map iterator over nothing
613     */
614    public static <K, V> OrderedMapIterator<K, V> emptyOrderedMapIterator() {
615        return EmptyOrderedMapIterator.<K, V>emptyOrderedMapIterator();
616    }
617
618    // Filtered
619    /**
620     * Gets an iterator that filters another iterator.
621     * <p>
622     * The returned iterator will only return objects that match the specified
623     * filtering predicate.
624     *
625     * @param <E> the element type
626     * @param iterator  the iterator to use, not null
627     * @param predicate  the predicate to use as a filter, not null
628     * @return a new filtered iterator
629     * @throws NullPointerException if either parameter is null
630     */
631    public static <E> Iterator<E> filteredIterator(final Iterator<? extends E> iterator,
632                                                   final Predicate<? super E> predicate) {
633        Objects.requireNonNull(iterator, "iterator");
634        Objects.requireNonNull(predicate, "predicate");
635        return new FilterIterator<>(iterator, predicate);
636    }
637
638    /**
639     * Gets a list iterator that filters another list iterator.
640     * <p>
641     * The returned iterator will only return objects that match the specified
642     * filtering predicate.
643     *
644     * @param <E> the element type
645     * @param listIterator  the list iterator to use, not null
646     * @param predicate  the predicate to use as a filter, not null
647     * @return a new filtered iterator
648     * @throws NullPointerException if either parameter is null
649     */
650    public static <E> ListIterator<E> filteredListIterator(final ListIterator<? extends E> listIterator,
651            final Predicate<? super E> predicate) {
652
653        Objects.requireNonNull(listIterator, "listIterator");
654        Objects.requireNonNull(predicate, "predicate");
655        return new FilterListIterator<>(listIterator, predicate);
656    }
657
658    /**
659     * Finds the first element in the given iterator which matches the given predicate.
660     * <p>
661     * A {@code null} or empty iterator returns null.
662     *
663     * @param <E> the element type
664     * @param iterator  the iterator to search, may be null
665     * @param predicate  the predicate to use, must not be null
666     * @return the first element of the iterator which matches the predicate or null if none could be found
667     * @throws NullPointerException if predicate is null
668     * @since 4.1
669     */
670    public static <E> E find(final Iterator<E> iterator, final Predicate<? super E> predicate) {
671        Objects.requireNonNull(predicate, "predicate");
672
673        if (iterator != null) {
674            while (iterator.hasNext()) {
675                final E element = iterator.next();
676                if (predicate.evaluate(element)) {
677                    return element;
678                }
679            }
680        }
681        return null;
682    }
683
684    /**
685     * Shortcut for {@code get(iterator, 0)}.
686     * <p>
687     * Returns the {@code first} value in {@link Iterator}, throwing
688     * {@code IndexOutOfBoundsException} if there is no such element.
689     * </p>
690     * <p>
691     * The Iterator is advanced to {@code 0} (or to the end, if
692     * {@code 0} exceeds the number of entries) as a side effect of this method.
693     * </p>
694     * @param <E> the type of object in the {@link Iterator}
695     * @param iterator the iterator to get a value from
696     * @return the first object
697     * @throws IndexOutOfBoundsException if the request is invalid
698     * @since 4.2
699     */
700    public static <E> E first(final Iterator<E> iterator) {
701        return get(iterator, 0);
702    }
703
704    /**
705     * Applies the closure to each element of the provided iterator.
706     *
707     * @param <E> the element type
708     * @param iterator  the iterator to use, may be null
709     * @param closure  the closure to apply to each element, may not be null
710     * @throws NullPointerException if closure is null
711     * @since 4.1
712     */
713    public static <E> void forEach(final Iterator<E> iterator, final Closure<? super E> closure) {
714        Objects.requireNonNull(closure, "closure");
715
716        if (iterator != null) {
717            while (iterator.hasNext()) {
718                final E element = iterator.next();
719                closure.execute(element);
720            }
721        }
722    }
723
724    /**
725     * Executes the given closure on each but the last element in the iterator.
726     * <p>
727     * If the input iterator is null no change is made.
728     *
729     * @param <E> the type of object the {@link Iterator} contains
730     * @param iterator  the iterator to get the input from, may be null
731     * @param closure  the closure to perform, may not be null
732     * @return the last element in the iterator, or null if iterator is null or empty
733     * @throws NullPointerException if closure is null
734     * @since 4.1
735     */
736    public static <E> E forEachButLast(final Iterator<E> iterator, final Closure<? super E> closure) {
737        Objects.requireNonNull(closure, "closure");
738
739        if (iterator != null) {
740            while (iterator.hasNext()) {
741                final E element = iterator.next();
742                if (!iterator.hasNext()) {
743                    return element;
744                }
745                closure.execute(element);
746            }
747        }
748        return null;
749    }
750
751    /**
752     * Returns the {@code index}-th value in {@link Iterator}, throwing
753     * {@code IndexOutOfBoundsException} if there is no such element.
754     * <p>
755     * The Iterator is advanced to {@code index} (or to the end, if
756     * {@code index} exceeds the number of entries) as a side effect of this method.
757     *
758     * @param <E> the type of object in the {@link Iterator}
759     * @param iterator  the iterator to get a value from
760     * @param index  the index to get
761     * @return the object at the specified index
762     * @throws IndexOutOfBoundsException if the index is invalid
763     * @since 4.1
764     */
765    public static <E> E get(final Iterator<E> iterator, final int index) {
766        int i = index;
767        CollectionUtils.checkIndexBounds(i);
768        while (iterator.hasNext()) {
769            i--;
770            if (i == -1) {
771                return iterator.next();
772            }
773            iterator.next();
774        }
775        throw new IndexOutOfBoundsException("Entry does not exist: " + i);
776    }
777
778    /**
779     * Gets a suitable Iterator for the given object.
780     * <p>
781     * This method can handle objects as follows
782     * <ul>
783     * <li>null - empty iterator
784     * <li>Iterator - returned directly
785     * <li>Enumeration - wrapped
786     * <li>Collection - iterator from collection returned
787     * <li>Map - values iterator returned
788     * <li>Dictionary - values (elements) enumeration returned as iterator
789     * <li>array - iterator over array returned
790     * <li>object with iterator() public method accessed by reflection
791     * <li>object - singleton iterator
792     * <li>NodeList - iterator over the list
793     * <li>Node - iterator over the child nodes
794     * </ul>
795     *
796     * @param obj  the object to convert to an iterator
797     * @return a suitable iterator, never null
798     */
799    public static Iterator<?> getIterator(final Object obj) {
800        if (obj == null) {
801            return emptyIterator();
802        }
803        if (obj instanceof Iterator) {
804            return (Iterator<?>) obj;
805        }
806        if (obj instanceof Iterable) {
807            return ((Iterable<?>) obj).iterator();
808        }
809        if (obj instanceof Object[]) {
810            return new ObjectArrayIterator<>((Object[]) obj);
811        }
812        if (obj instanceof Enumeration) {
813            return new EnumerationIterator<>((Enumeration<?>) obj);
814        }
815        if (obj instanceof Map) {
816            return ((Map<?, ?>) obj).values().iterator();
817        }
818        if (obj instanceof NodeList) {
819            return new NodeListIterator((NodeList) obj);
820        }
821        if (obj instanceof Node) {
822            return new NodeListIterator((Node) obj);
823        }
824        if (obj instanceof Dictionary) {
825            return new EnumerationIterator<>(((Dictionary<?, ?>) obj).elements());
826        }
827        if (obj.getClass().isArray()) {
828            return new ArrayIterator<>(obj);
829        }
830        try {
831            final Method method = obj.getClass().getMethod("iterator", (Class[]) null);
832            if (Iterator.class.isAssignableFrom(method.getReturnType())) {
833                final Iterator<?> it = (Iterator<?>) method.invoke(obj, (Object[]) null);
834                if (it != null) {
835                    return it;
836                }
837            }
838        } catch (final RuntimeException | ReflectiveOperationException ignore) { // NOPMD
839            // ignore
840        }
841        return singletonIterator(obj);
842    }
843
844    // Peeking
845
846    /**
847     * Returns the index of the first element in the specified iterator that
848     * matches the given predicate.
849     * <p>
850     * A {@code null} or empty iterator returns -1.
851     *
852     * @param <E> the element type
853     * @param iterator  the iterator to search, may be null
854     * @param predicate  the predicate to use, may not be null
855     * @return the index of the first element which matches the predicate or -1 if none matches
856     * @throws NullPointerException if predicate is null
857     * @since 4.1
858     */
859    public static <E> int indexOf(final Iterator<E> iterator, final Predicate<? super E> predicate) {
860        Objects.requireNonNull(predicate, "predicate");
861
862        if (iterator != null) {
863            for (int index = 0; iterator.hasNext(); index++) {
864                final E element = iterator.next();
865                if (predicate.evaluate(element)) {
866                    return index;
867                }
868            }
869        }
870        return CollectionUtils.INDEX_NOT_FOUND;
871    }
872
873    // Pushback
874
875    /**
876     * Checks if the given iterator is empty.
877     * <p>
878     * A {@code null} or empty iterator returns true.
879     *
880     * @param iterator  the {@link Iterator} to use, may be null
881     * @return true if the iterator is exhausted or null, false otherwise
882     * @since 4.1
883     */
884    public static boolean isEmpty(final Iterator<?> iterator) {
885        return iterator == null || !iterator.hasNext();
886    }
887
888    // Looping
889    /**
890     * Gets an iterator that loops continuously over the supplied collection.
891     * <p>
892     * The iterator will only stop looping if the remove method is called
893     * enough times to empty the collection, or if the collection is empty
894     * to start with.
895     *
896     * @param <E> the element type
897     * @param collection  the collection to iterate over, not null
898     * @return a new looping iterator
899     * @throws NullPointerException if the collection is null
900     */
901    public static <E> ResettableIterator<E> loopingIterator(final Collection<? extends E> collection) {
902        return new LoopingIterator<>(Objects.requireNonNull(collection, "collection"));
903    }
904
905    /**
906     * Gets an iterator that loops continuously over the supplied list.
907     * <p>
908     * The iterator will only stop looping if the remove method is called
909     * enough times to empty the list, or if the list is empty to start with.
910     *
911     * @param <E> the element type
912     * @param list  the list to iterate over, not null
913     * @return a new looping iterator
914     * @throws NullPointerException if the list is null
915     * @since 3.2
916     */
917    public static <E> ResettableListIterator<E> loopingListIterator(final List<E> list) {
918        return new LoopingListIterator<>(Objects.requireNonNull(list, "list"));
919    }
920
921    /**
922     * Answers true if a predicate is true for every element of an iterator.
923     * <p>
924     * A {@code null} or empty iterator returns true.
925     *
926     * @param <E> the type of object the {@link Iterator} contains
927     * @param iterator  the {@link Iterator} to use, may be null
928     * @param predicate  the predicate to use, may not be null
929     * @return true if every element of the collection matches the predicate or if the
930     *   collection is empty, false otherwise
931     * @throws NullPointerException if predicate is null
932     * @since 4.1
933     */
934    public static <E> boolean matchesAll(final Iterator<E> iterator, final Predicate<? super E> predicate) {
935        Objects.requireNonNull(predicate, "predicate");
936
937        if (iterator != null) {
938            while (iterator.hasNext()) {
939                final E element = iterator.next();
940                if (!predicate.evaluate(element)) {
941                    return false;
942                }
943            }
944        }
945        return true;
946    }
947
948    /**
949     * Answers true if a predicate is true for any element of the iterator.
950     * <p>
951     * A {@code null} or empty iterator returns false.
952     *
953     * @param <E> the type of object the {@link Iterator} contains
954     * @param iterator  the {@link Iterator} to use, may be null
955     * @param predicate  the predicate to use, may not be null
956     * @return true if any element of the collection matches the predicate, false otherwise
957     * @throws NullPointerException if predicate is null
958     * @since 4.1
959     */
960    public static <E> boolean matchesAny(final Iterator<E> iterator, final Predicate<? super E> predicate) {
961        return indexOf(iterator, predicate) != -1;
962    }
963
964    /**
965     * Gets an {@link Iterator} that wraps the specified node's childNodes.
966     * The returned {@link Iterator} can be used for a single iteration.
967     * <p>
968     * Convenience method, allows easy iteration over NodeLists:
969     * <pre>
970     *   Iterator&lt;Node&gt; iterator = IteratorUtils.nodeListIterator(node);
971     *   for (Node childNode : IteratorUtils.asIterable(iterator)) {
972     *     ...
973     *   }
974     * </pre>
975     *
976     * @param node  the node to use, may not be null
977     * @return a new, single use {@link Iterator}
978     * @throws NullPointerException if node is null
979     * @since 4.0
980     */
981    public static NodeListIterator nodeListIterator(final Node node) {
982        return new NodeListIterator(Objects.requireNonNull(node, "node"));
983    }
984
985    // org.w3c.dom.NodeList iterators
986    /**
987     * Gets an {@link Iterator} that wraps the specified {@link NodeList}.
988     * The returned {@link Iterator} can be used for a single iteration.
989     *
990     * @param nodeList  the node list to use, may not be null
991     * @return a new, single use {@link Iterator}
992     * @throws NullPointerException if nodeList is null
993     * @since 4.0
994     */
995    public static NodeListIterator nodeListIterator(final NodeList nodeList) {
996        return new NodeListIterator(Objects.requireNonNull(nodeList, "nodeList"));
997    }
998
999    // Object Graph
1000    /**
1001     * Gets an iterator that operates over an object graph.
1002     * <p>
1003     * This iterator can extract multiple objects from a complex tree-like object graph.
1004     * The iteration starts from a single root object.
1005     * It uses a {@code Transformer} to extract the iterators and elements.
1006     * Its main benefit is that no intermediate {@code List} is created.
1007     * <p>
1008     * For example, consider an object graph:
1009     * <pre>
1010     *                 |- Branch -- Leaf
1011     *                 |         \- Leaf
1012     *         |- Tree |         /- Leaf
1013     *         |       |- Branch -- Leaf
1014     *  Forest |                 \- Leaf
1015     *         |       |- Branch -- Leaf
1016     *         |       |         \- Leaf
1017     *         |- Tree |         /- Leaf
1018     *                 |- Branch -- Leaf
1019     *                 |- Branch -- Leaf</pre>
1020     * The following {@code Transformer}, used in this class, will extract all
1021     * the Leaf objects without creating a combined intermediate list:
1022     * <pre>
1023     * public Object transform(Object input) {
1024     *   if (input instanceof Forest) {
1025     *     return ((Forest) input).treeIterator();
1026     *   }
1027     *   if (input instanceof Tree) {
1028     *     return ((Tree) input).branchIterator();
1029     *   }
1030     *   if (input instanceof Branch) {
1031     *     return ((Branch) input).leafIterator();
1032     *   }
1033     *   if (input instanceof Leaf) {
1034     *     return input;
1035     *   }
1036     *   throw new ClassCastException();
1037     * }</pre>
1038     * <p>
1039     * Internally, iteration starts from the root object. When next is called,
1040     * the transformer is called to examine the object. The transformer will return
1041     * either an iterator or an object. If the object is an Iterator, the next element
1042     * from that iterator is obtained and the process repeats. If the element is an object
1043     * it is returned.
1044     * <p>
1045     * Under many circumstances, linking Iterators together in this manner is
1046     * more efficient (and convenient) than using nested for loops to extract a list.
1047     *
1048     * @param <E> the element type
1049     * @param root  the root object to start iterating from, null results in an empty iterator
1050     * @param transformer  the transformer to use, see above, null uses no effect transformer
1051     * @return a new object graph iterator
1052     * @since 3.1
1053     */
1054    public static <E> Iterator<E> objectGraphIterator(final E root,
1055            final Transformer<? super E, ? extends E> transformer) {
1056        return new ObjectGraphIterator<>(root, transformer);
1057    }
1058
1059    /**
1060     * Gets an iterator that supports one-element lookahead.
1061     *
1062     * @param <E> the element type
1063     * @param iterator  the iterator to decorate, not null
1064     * @return a peeking iterator
1065     * @throws NullPointerException if the iterator is null
1066     * @since 4.0
1067     */
1068    public static <E> Iterator<E> peekingIterator(final Iterator<? extends E> iterator) {
1069        return PeekingIterator.peekingIterator(iterator);
1070    }
1071
1072    /**
1073     * Gets an iterator that supports pushback of elements.
1074     *
1075     * @param <E> the element type
1076     * @param iterator  the iterator to decorate, not null
1077     * @return a pushback iterator
1078     * @throws NullPointerException if the iterator is null
1079     * @since 4.0
1080     */
1081    public static <E> Iterator<E> pushbackIterator(final Iterator<? extends E> iterator) {
1082        return PushbackIterator.pushbackIterator(iterator);
1083    }
1084
1085    // Singleton
1086    /**
1087     * Gets a singleton iterator.
1088     * <p>
1089     * This iterator is a valid iterator object that will iterate over
1090     * the specified object.
1091     *
1092     * @param <E> the element type
1093     * @param object  the single object over which to iterate
1094     * @return a singleton iterator over the object
1095     */
1096    public static <E> ResettableIterator<E> singletonIterator(final E object) {
1097        return new SingletonIterator<>(object);
1098    }
1099
1100    /**
1101     * Gets a singleton list iterator.
1102     * <p>
1103     * This iterator is a valid list iterator object that will iterate over
1104     * the specified object.
1105     *
1106     * @param <E> the element type
1107     * @param object  the single object over which to iterate
1108     * @return a singleton list iterator over the object
1109     */
1110    public static <E> ListIterator<E> singletonListIterator(final E object) {
1111        return new SingletonListIterator<>(object);
1112    }
1113
1114    /**
1115     * Returns the number of elements contained in the given iterator.
1116     * <p>
1117     * A {@code null} or empty iterator returns {@code 0}.
1118     *
1119     * @param iterator  the iterator to check, may be null
1120     * @return the number of elements contained in the iterator
1121     * @since 4.1
1122     */
1123    public static int size(final Iterator<?> iterator) {
1124        int size = 0;
1125        if (iterator != null) {
1126            while (iterator.hasNext()) {
1127                iterator.next();
1128                size++;
1129            }
1130        }
1131        return size;
1132    }
1133
1134    // Skipping
1135    /**
1136     * Decorates the specified iterator to skip the first N elements.
1137     *
1138     * @param <E> the element type
1139     * @param iterator  the iterator to decorate
1140     * @param offset  the first number of elements to skip
1141     * @return a new skipping iterator
1142     * @throws NullPointerException if the iterator is null
1143     * @throws IllegalArgumentException if offset is negative
1144     * @since 4.1
1145     */
1146    public static <E> SkippingIterator<E> skippingIterator(final Iterator<E> iterator, final long offset) {
1147        return new SkippingIterator<>(iterator, offset);
1148    }
1149
1150    /**
1151     * Gets an array based on an iterator.
1152     * <p>
1153     * As the wrapped Iterator is traversed, an ArrayList of its values is
1154     * created. At the end, this is converted to an array.
1155     *
1156     * @param iterator  the iterator to use, not null
1157     * @return an array of the iterator contents
1158     * @throws NullPointerException if iterator parameter is null
1159     */
1160    public static Object[] toArray(final Iterator<?> iterator) {
1161        Objects.requireNonNull(iterator, "iterator");
1162        final List<?> list = toList(iterator, 100);
1163        return list.toArray();
1164    }
1165
1166    /**
1167     * Gets an array based on an iterator.
1168     * <p>
1169     * As the wrapped Iterator is traversed, an ArrayList of its values is
1170     * created. At the end, this is converted to an array.
1171     *
1172     * @param <E> the element type
1173     * @param iterator  the iterator to use, not null
1174     * @param arrayClass  the class of array to create
1175     * @return an array of the iterator contents
1176     * @throws NullPointerException if iterator parameter or arrayClass is null
1177     * @throws ArrayStoreException if the arrayClass is invalid
1178     */
1179    public static <E> E[] toArray(final Iterator<? extends E> iterator, final Class<E> arrayClass) {
1180        Objects.requireNonNull(iterator, "iterator");
1181        Objects.requireNonNull(arrayClass, "arrayClass");
1182        final List<E> list = toList(iterator, 100);
1183        @SuppressWarnings("unchecked")
1184        final E[] array = (E[]) Array.newInstance(arrayClass, list.size());
1185        return list.toArray(array);
1186    }
1187
1188    // Utility methods
1189
1190    /**
1191     * Gets a list based on an iterator.
1192     * <p>
1193     * As the wrapped Iterator is traversed, an ArrayList of its values is
1194     * created. At the end, the list is returned.
1195     *
1196     * @param <E> the element type
1197     * @param iterator  the iterator to use, not null
1198     * @return a list of the iterator contents
1199     * @throws NullPointerException if iterator parameter is null
1200     */
1201    public static <E> List<E> toList(final Iterator<? extends E> iterator) {
1202        return toList(iterator, 10);
1203    }
1204
1205    /**
1206     * Gets a list based on an iterator.
1207     * <p>
1208     * As the wrapped Iterator is traversed, an ArrayList of its values is
1209     * created. At the end, the list is returned.
1210     *
1211     * @param <E> the element type
1212     * @param iterator  the iterator to use, not null
1213     * @param estimatedSize  the initial size of the ArrayList
1214     * @return a list of the iterator contents
1215     * @throws NullPointerException if iterator parameter is null
1216     * @throws IllegalArgumentException if the size is less than 1
1217     */
1218    public static <E> List<E> toList(final Iterator<? extends E> iterator, final int estimatedSize) {
1219        Objects.requireNonNull(iterator, "iterator");
1220        if (estimatedSize < 1) {
1221            throw new IllegalArgumentException("Estimated size must be greater than 0");
1222        }
1223        final List<E> list = new ArrayList<>(estimatedSize);
1224        while (iterator.hasNext()) {
1225            list.add(iterator.next());
1226        }
1227        return list;
1228    }
1229
1230    /**
1231     * Gets a list iterator based on a simple iterator.
1232     * <p>
1233     * As the wrapped Iterator is traversed, a LinkedList of its values is
1234     * cached, permitting all required operations of ListIterator.
1235     *
1236     * @param <E> the element type
1237     * @param iterator  the iterator to use, may not be null
1238     * @return a new iterator
1239     * @throws NullPointerException if iterator parameter is null
1240     */
1241    public static <E> ListIterator<E> toListIterator(final Iterator<? extends E> iterator) {
1242        Objects.requireNonNull(iterator, "iterator");
1243        return new ListIteratorWrapper<>(iterator);
1244    }
1245
1246    /**
1247     * Returns a string representation of the elements of the specified iterator.
1248     * <p>
1249     * The string representation consists of a list of the iterator's elements,
1250     * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated
1251     * by the characters {@code ", "} (a comma followed by a space). Elements are
1252     * converted to strings as by {@code String.valueOf(Object)}.
1253     *
1254     * @param <E> the element type
1255     * @param iterator  the iterator to convert to a string, may be null
1256     * @return a string representation of {@code iterator}
1257     * @since 4.1
1258     */
1259    public static <E> String toString(final Iterator<E> iterator) {
1260        return toString(iterator, TransformerUtils.stringValueTransformer(),
1261                        DEFAULT_TOSTRING_DELIMITER, CollectionUtils.DEFAULT_TOSTRING_PREFIX,
1262                CollectionUtils.DEFAULT_TOSTRING_SUFFIX);
1263    }
1264
1265    /**
1266     * Returns a string representation of the elements of the specified iterator.
1267     * <p>
1268     * The string representation consists of a list of the iterable's elements,
1269     * enclosed in square brackets ({@code "[]"}). Adjacent elements are separated
1270     * by the characters {@code ", "} (a comma followed by a space). Elements are
1271     * converted to strings as by using the provided {@code transformer}.
1272     *
1273     * @param <E> the element type
1274     * @param iterator  the iterator to convert to a string, may be null
1275     * @param transformer  the transformer used to get a string representation of an element
1276     * @return a string representation of {@code iterator}
1277     * @throws NullPointerException if {@code transformer} is null
1278     * @since 4.1
1279     */
1280    public static <E> String toString(final Iterator<E> iterator,
1281                                      final Transformer<? super E, String> transformer) {
1282        return toString(iterator, transformer, DEFAULT_TOSTRING_DELIMITER,
1283                CollectionUtils.DEFAULT_TOSTRING_PREFIX, CollectionUtils.DEFAULT_TOSTRING_SUFFIX);
1284    }
1285
1286    /**
1287     * Returns a string representation of the elements of the specified iterator.
1288     * <p>
1289     * The string representation consists of a list of the iterator's elements,
1290     * enclosed by the provided {@code prefix} and {@code suffix}. Adjacent elements
1291     * are separated by the provided {@code delimiter}. Elements are converted to
1292     * strings as by using the provided {@code transformer}.
1293     *
1294     * @param <E> the element type
1295     * @param iterator  the iterator to convert to a string, may be null
1296     * @param transformer  the transformer used to get a string representation of an element
1297     * @param delimiter  the string to delimit elements
1298     * @param prefix  the prefix, prepended to the string representation
1299     * @param suffix  the suffix, appended to the string representation
1300     * @return a string representation of {@code iterator}
1301     * @throws NullPointerException if either transformer, delimiter, prefix or suffix is null
1302     * @since 4.1
1303     */
1304    public static <E> String toString(final Iterator<E> iterator,
1305                                      final Transformer<? super E, String> transformer,
1306                                      final String delimiter,
1307                                      final String prefix,
1308                                      final String suffix) {
1309        Objects.requireNonNull(transformer, "transformer");
1310        Objects.requireNonNull(delimiter, "delimiter");
1311        Objects.requireNonNull(prefix, "prefix");
1312        Objects.requireNonNull(suffix, "suffix");
1313        final StringBuilder stringBuilder = new StringBuilder(prefix);
1314        if (iterator != null) {
1315            while (iterator.hasNext()) {
1316                final E element = iterator.next();
1317                stringBuilder.append(transformer.transform(element));
1318                stringBuilder.append(delimiter);
1319            }
1320            if (stringBuilder.length() > prefix.length()) {
1321                stringBuilder.setLength(stringBuilder.length() - delimiter.length());
1322            }
1323        }
1324        stringBuilder.append(suffix);
1325        return stringBuilder.toString();
1326    }
1327
1328    // Transformed
1329    /**
1330     * Gets an iterator that transforms the elements of another iterator.
1331     * <p>
1332     * The transformation occurs during the next() method and the underlying
1333     * iterator is unaffected by the transformation.
1334     *
1335     * @param <I> the input type
1336     * @param <O> the output type
1337     * @param iterator  the iterator to use, not null
1338     * @param transformer  the transform to use, not null
1339     * @return a new transforming iterator
1340     * @throws NullPointerException if either parameter is null
1341     */
1342    public static <I, O> Iterator<O> transformedIterator(final Iterator<? extends I> iterator,
1343            final Transformer<? super I, ? extends O> transformer) {
1344
1345        Objects.requireNonNull(iterator, "iterator");
1346        Objects.requireNonNull(transformer, "transformer");
1347        return new TransformIterator<>(iterator, transformer);
1348    }
1349
1350    // Unmodifiable
1351    /**
1352     * Gets an immutable version of an {@link Iterator}. The returned object
1353     * will always throw an {@link UnsupportedOperationException} for
1354     * the {@link Iterator#remove} method.
1355     *
1356     * @param <E> the element type
1357     * @param iterator  the iterator to make immutable
1358     * @return an immutable version of the iterator
1359     */
1360    public static <E> Iterator<E> unmodifiableIterator(final Iterator<E> iterator) {
1361        return UnmodifiableIterator.unmodifiableIterator(iterator);
1362    }
1363
1364    /**
1365     * Gets an immutable version of a {@link ListIterator}. The returned object
1366     * will always throw an {@link UnsupportedOperationException} for
1367     * the {@link Iterator#remove}, {@link ListIterator#add} and
1368     * {@link ListIterator#set} methods.
1369     *
1370     * @param <E> the element type
1371     * @param listIterator  the iterator to make immutable
1372     * @return an immutable version of the iterator
1373     */
1374    public static <E> ListIterator<E> unmodifiableListIterator(final ListIterator<E> listIterator) {
1375        return UnmodifiableListIterator.unmodifiableListIterator(listIterator);
1376    }
1377
1378    /**
1379     * Gets an immutable version of a {@link MapIterator}. The returned object
1380     * will always throw an {@link UnsupportedOperationException} for
1381     * the {@link Iterator#remove}, {@link MapIterator#setValue(Object)} methods.
1382     *
1383     * @param <K> the key type
1384     * @param <V> the value type
1385     * @param mapIterator  the iterator to make immutable
1386     * @return an immutable version of the iterator
1387     */
1388    public static <K, V> MapIterator<K, V> unmodifiableMapIterator(final MapIterator<K, V> mapIterator) {
1389        return UnmodifiableMapIterator.unmodifiableMapIterator(mapIterator);
1390    }
1391
1392    /**
1393     * Returns an iterator that interleaves elements from the decorated iterators.
1394     *
1395     * @param <E> the element type
1396     * @param iterators  the array of iterators to interleave
1397     * @return an iterator, interleaving the decorated iterators
1398     * @throws NullPointerException if any iterator is null
1399     * @since 4.1
1400     */
1401    public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E>... iterators) {
1402        return new ZippingIterator<>(iterators);
1403    }
1404
1405    // Zipping
1406    /**
1407     * Returns an iterator that interleaves elements from the decorated iterators.
1408     *
1409     * @param <E> the element type
1410     * @param a  the first iterator to interleave
1411     * @param b  the second iterator to interleave
1412     * @return an iterator, interleaving the decorated iterators
1413     * @throws NullPointerException if any iterator is null
1414     * @since 4.1
1415     */
1416    public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E> a,
1417                                                         final Iterator<? extends E> b) {
1418        return new ZippingIterator<>(a, b);
1419    }
1420
1421    /**
1422     * Returns an iterator that interleaves elements from the decorated iterators.
1423     *
1424     * @param <E> the element type
1425     * @param a  the first iterator to interleave
1426     * @param b  the second iterator to interleave
1427     * @param c  the third iterator to interleave
1428     * @return an iterator, interleaving the decorated iterators
1429     * @throws NullPointerException if any iterator is null
1430     * @since 4.1
1431     */
1432    public static <E> ZippingIterator<E> zippingIterator(final Iterator<? extends E> a,
1433                                                         final Iterator<? extends E> b,
1434                                                         final Iterator<? extends E> c) {
1435        return new ZippingIterator<>(a, b, c);
1436    }
1437
1438    /**
1439     * Don't allow instances.
1440     */
1441    private IteratorUtils() {}
1442
1443}