1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections;
18
19 import java.lang.reflect.Array;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.Dictionary;
26 import java.util.Enumeration;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.ListIterator;
30 import java.util.Map;
31
32 import org.apache.commons.collections.iterators.ArrayIterator;
33 import org.apache.commons.collections.iterators.ArrayListIterator;
34 import org.apache.commons.collections.iterators.CollatingIterator;
35 import org.apache.commons.collections.iterators.EmptyIterator;
36 import org.apache.commons.collections.iterators.EmptyListIterator;
37 import org.apache.commons.collections.iterators.EmptyMapIterator;
38 import org.apache.commons.collections.iterators.EmptyOrderedIterator;
39 import org.apache.commons.collections.iterators.EmptyOrderedMapIterator;
40 import org.apache.commons.collections.iterators.EnumerationIterator;
41 import org.apache.commons.collections.iterators.FilterIterator;
42 import org.apache.commons.collections.iterators.FilterListIterator;
43 import org.apache.commons.collections.iterators.IteratorChain;
44 import org.apache.commons.collections.iterators.IteratorEnumeration;
45 import org.apache.commons.collections.iterators.IteratorIterable;
46 import org.apache.commons.collections.iterators.ListIteratorWrapper;
47 import org.apache.commons.collections.iterators.LoopingIterator;
48 import org.apache.commons.collections.iterators.LoopingListIterator;
49 import org.apache.commons.collections.iterators.NodeListIterator;
50 import org.apache.commons.collections.iterators.ObjectArrayIterator;
51 import org.apache.commons.collections.iterators.ObjectArrayListIterator;
52 import org.apache.commons.collections.iterators.ObjectGraphIterator;
53 import org.apache.commons.collections.iterators.SingletonIterator;
54 import org.apache.commons.collections.iterators.SingletonListIterator;
55 import org.apache.commons.collections.iterators.TransformIterator;
56 import org.apache.commons.collections.iterators.UnmodifiableIterator;
57 import org.apache.commons.collections.iterators.UnmodifiableListIterator;
58 import org.apache.commons.collections.iterators.UnmodifiableMapIterator;
59 import org.w3c.dom.Node;
60 import org.w3c.dom.NodeList;
61
62 /**
63 * Provides static utility methods and decorators for {@link Iterator}
64 * instances. The implementations are provided in the iterators subpackage.
65 * <p>
66 * WARNING: Due to human error certain binary incompatibilities were introduced
67 * between Commons Collections 2.1 and 3.0. The class remained source and test
68 * compatible, so if you can recompile all your classes and dependencies
69 * everything is OK. Those methods which are binary incompatible are marked as
70 * such, together with alternate solutions that are binary compatible
71 * against versions 2.1.1 and 3.1.
72 *
73 * @since 2.1
74 * @version $Id: IteratorUtils.java 1439046 2013-01-27 10:35:24Z tn $
75 */
76 public class IteratorUtils {
77 // validation is done in this class in certain cases because the
78 // public classes allow invalid states
79
80 /**
81 * An iterator over no elements.
82 * <p>
83 * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
84 * Use <code>EmptyIterator.INSTANCE</code> for compatibility with Commons Collections 2.1.1.
85 */
86 public static final ResettableIterator<Object> EMPTY_ITERATOR = EmptyIterator.RESETTABLE_INSTANCE;
87
88 /**
89 * A list iterator over no elements.
90 * <p>
91 * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
92 * Use <code>EmptyListIterator.INSTANCE</code> for compatibility with Commons Collections 2.1.1.
93 */
94 public static final ResettableListIterator<Object> EMPTY_LIST_ITERATOR = EmptyListIterator.RESETTABLE_INSTANCE;
95
96 /**
97 * An ordered iterator over no elements.
98 */
99 public static final OrderedIterator<Object> EMPTY_ORDERED_ITERATOR = EmptyOrderedIterator.INSTANCE;
100
101 /**
102 * A map iterator over no elements.
103 */
104 public static final MapIterator<Object, Object> EMPTY_MAP_ITERATOR = EmptyMapIterator.INSTANCE;
105
106 /**
107 * An ordered map iterator over no elements.
108 */
109 public static final OrderedMapIterator<Object, Object> EMPTY_ORDERED_MAP_ITERATOR =
110 EmptyOrderedMapIterator.INSTANCE;
111
112 /**
113 * IteratorUtils is not normally instantiated.
114 */
115 public IteratorUtils() {
116 }
117
118 // Empty
119 //-----------------------------------------------------------------------
120 /**
121 * Gets an empty iterator.
122 * <p>
123 * This iterator is a valid iterator object that will iterate over
124 * nothing.
125 * <p>
126 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
127 * Use <code>EmptyIterator.INSTANCE</code> for compatibility with Commons Collections 2.1.1.
128 *
129 * @param <E> the element type
130 * @return an iterator over nothing
131 */
132 public static <E> ResettableIterator<E> emptyIterator() {
133 return EmptyIterator.<E>resettableEmptyIterator();
134 }
135
136 /**
137 * Gets an empty list iterator.
138 * <p>
139 * This iterator is a valid list iterator object that will iterate
140 * over nothing.
141 * <p>
142 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
143 * Use <code>EmptyListIterator.INSTANCE</code> for compatibility with Commons Collections 2.1.1.
144 *
145 * @param <E> the element type
146 * @return a list iterator over nothing
147 */
148 public static <E> ResettableListIterator<E> emptyListIterator() {
149 return EmptyListIterator.<E>resettableEmptyListIterator();
150 }
151
152 /**
153 * Gets an empty ordered iterator.
154 * <p>
155 * This iterator is a valid iterator object that will iterate
156 * over nothing.
157 *
158 * @param <E> the element type
159 * @return an ordered iterator over nothing
160 */
161 public static <E> OrderedIterator<E> emptyOrderedIterator() {
162 return EmptyOrderedIterator.<E>emptyOrderedIterator();
163 }
164
165 /**
166 * Gets an empty map iterator.
167 * <p>
168 * This iterator is a valid map iterator object that will iterate
169 * over nothing.
170 *
171 * @param <K> the key type
172 * @param <V> the value type
173 * @return a map iterator over nothing
174 */
175 public static <K, V> MapIterator<K, V> emptyMapIterator() {
176 return EmptyMapIterator.<K, V>emptyMapIterator();
177 }
178
179 /**
180 * Gets an empty ordered map iterator.
181 * <p>
182 * This iterator is a valid map iterator object that will iterate
183 * over nothing.
184 *
185 * @param <K> the key type
186 * @param <V> the value type
187 * @return a map iterator over nothing
188 */
189 public static <K, V> OrderedMapIterator<K, V> emptyOrderedMapIterator() {
190 return EmptyOrderedMapIterator.<K, V>emptyOrderedMapIterator();
191 }
192
193 // Singleton
194 //-----------------------------------------------------------------------
195 /**
196 * Gets a singleton iterator.
197 * <p>
198 * This iterator is a valid iterator object that will iterate over
199 * the specified object.
200 * <p>
201 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
202 * Use <code>new SingletonIterator(object)</code> for compatibility.
203 *
204 * @param <E> the element type
205 * @param object the single object over which to iterate
206 * @return a singleton iterator over the object
207 */
208 public static <E> ResettableIterator<E> singletonIterator(final E object) {
209 return new SingletonIterator<E>(object);
210 }
211
212 /**
213 * Gets a singleton list iterator.
214 * <p>
215 * This iterator is a valid list iterator object that will iterate over
216 * the specified object.
217 *
218 * @param <E> the element type
219 * @param object the single object over which to iterate
220 * @return a singleton list iterator over the object
221 */
222 public static <E> ListIterator<E> singletonListIterator(final E object) {
223 return new SingletonListIterator<E>(object);
224 }
225
226 // Arrays
227 //-----------------------------------------------------------------------
228 /**
229 * Gets an iterator over an object array.
230 * <p>
231 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
232 * Use <code>new ArrayIterator(array)</code> for compatibility.
233 *
234 * @param <E> the element type
235 * @param array the array over which to iterate
236 * @return an iterator over the array
237 * @throws NullPointerException if array is null
238 */
239 public static <E> ResettableIterator<E> arrayIterator(final E[] array) {
240 return new ObjectArrayIterator<E>(array);
241 }
242
243 /**
244 * Gets an iterator over an object or primitive array.
245 * <p>
246 * This method will handle primitive arrays as well as object arrays.
247 * The primitives will be wrapped in the appropriate wrapper class.
248 *
249 * @param <E> the element type
250 * @param array the array over which to iterate
251 * @return an iterator over the array
252 * @throws IllegalArgumentException if the array is not an array
253 * @throws NullPointerException if array is null
254 */
255 public static <E> ResettableIterator<E> arrayIterator(final Object array) {
256 return new ArrayIterator<E>(array);
257 }
258
259 /**
260 * Gets an iterator over the end part of an object array.
261 * <p>
262 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
263 * Use <code>new ArrayIterator(array,start)</code> for compatibility.
264 *
265 * @param <E> the element type
266 * @param array the array over which to iterate
267 * @param start the index to start iterating at
268 * @return an iterator over part of the array
269 * @throws IndexOutOfBoundsException if start is less than zero or greater
270 * than the length of the array
271 * @throws NullPointerException if array is null
272 */
273 public static <E> ResettableIterator<E> arrayIterator(final E[] array, final int start) {
274 return new ObjectArrayIterator<E>(array, start);
275 }
276
277 /**
278 * Gets an iterator over the end part of an object or primitive array.
279 * <p>
280 * This method will handle primitive arrays as well as object arrays.
281 * The primitives will be wrapped in the appropriate wrapper class.
282 *
283 * @param <E> the element type
284 * @param array the array over which to iterate
285 * @param start the index to start iterating at
286 * @return an iterator over part of the array
287 * @throws IllegalArgumentException if the array is not an array
288 * @throws IndexOutOfBoundsException if start is less than zero or greater
289 * than the length of the array
290 * @throws NullPointerException if array is null
291 */
292 public static <E> ResettableIterator<E> arrayIterator(final Object array, final int start) {
293 return new ArrayIterator<E>(array, start);
294 }
295
296 /**
297 * Gets an iterator over part of an object array.
298 * <p>
299 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
300 * Use <code>new ArrayIterator(array,start,end)</code> for compatibility.
301 *
302 * @param <E> the element type
303 * @param array the array over which to iterate
304 * @param start the index to start iterating at
305 * @param end the index to finish iterating at
306 * @return an iterator over part of the array
307 * @throws IndexOutOfBoundsException if array bounds are invalid
308 * @throws IllegalArgumentException if end is before start
309 * @throws NullPointerException if array is null
310 */
311 public static <E> ResettableIterator<E> arrayIterator(final E[] array, final int start, final int end) {
312 return new ObjectArrayIterator<E>(array, start, end);
313 }
314
315 /**
316 * Gets an iterator over part of an object or primitive array.
317 * <p>
318 * This method will handle primitive arrays as well as object arrays.
319 * The primitives will be wrapped in the appropriate wrapper class.
320 *
321 * @param <E> the element type
322 * @param array the array over which to iterate
323 * @param start the index to start iterating at
324 * @param end the index to finish iterating at
325 * @return an iterator over part of the array
326 * @throws IllegalArgumentException if the array is not an array or end is before start
327 * @throws IndexOutOfBoundsException if array bounds are invalid
328 * @throws NullPointerException if array is null
329 */
330 public static <E> ResettableIterator<E> arrayIterator(final Object array, final int start, final int end) {
331 return new ArrayIterator<E>(array, start, end);
332 }
333
334 //-----------------------------------------------------------------------
335 /**
336 * Gets a list iterator over an object array.
337 *
338 * @param <E> the element type
339 * @param array the array over which to iterate
340 * @return a list iterator over the array
341 * @throws NullPointerException if array is null
342 */
343 public static <E> ResettableListIterator<E> arrayListIterator(final E[] array) {
344 return new ObjectArrayListIterator<E>(array);
345 }
346
347 /**
348 * Gets a list iterator over an object or primitive array.
349 * <p>
350 * This method will handle primitive arrays as well as object arrays.
351 * The primitives will be wrapped in the appropriate wrapper class.
352 *
353 * @param <E> the element type
354 * @param array the array over which to iterate
355 * @return a list iterator over the array
356 * @throws IllegalArgumentException if the array is not an array
357 * @throws NullPointerException if array is null
358 */
359 public static <E> ResettableListIterator<E> arrayListIterator(final Object array) {
360 return new ArrayListIterator<E>(array);
361 }
362
363 /**
364 * Gets a list iterator over the end part of an object array.
365 *
366 * @param <E> the element type
367 * @param array the array over which to iterate
368 * @param start the index to start iterating at
369 * @return a list iterator over part of the array
370 * @throws IndexOutOfBoundsException if start is less than zero
371 * @throws NullPointerException if array is null
372 */
373 public static <E> ResettableListIterator<E> arrayListIterator(final E[] array, final int start) {
374 return new ObjectArrayListIterator<E>(array, start);
375 }
376
377 /**
378 * Gets a list iterator over the end part of an object or primitive array.
379 * <p>
380 * This method will handle primitive arrays as well as object arrays.
381 * The primitives will be wrapped in the appropriate wrapper class.
382 *
383 * @param <E> the element type
384 * @param array the array over which to iterate
385 * @param start the index to start iterating at
386 * @return a list iterator over part of the array
387 * @throws IllegalArgumentException if the array is not an array
388 * @throws IndexOutOfBoundsException if start is less than zero
389 * @throws NullPointerException if array is null
390 */
391 public static <E> ResettableListIterator<E> arrayListIterator(final Object array, final int start) {
392 return new ArrayListIterator<E>(array, start);
393 }
394
395 /**
396 * Gets a list iterator over part of an object array.
397 *
398 * @param <E> the element type
399 * @param array the array over which to iterate
400 * @param start the index to start iterating at
401 * @param end the index to finish iterating at
402 * @return a list iterator over part of the array
403 * @throws IndexOutOfBoundsException if array bounds are invalid
404 * @throws IllegalArgumentException if end is before start
405 * @throws NullPointerException if array is null
406 */
407 public static <E> ResettableListIterator<E> arrayListIterator(final E[] array, final int start, final int end) {
408 return new ObjectArrayListIterator<E>(array, start, end);
409 }
410
411 /**
412 * Gets a list iterator over part of an object or primitive array.
413 * <p>
414 * This method will handle primitive arrays as well as object arrays.
415 * The primitives will be wrapped in the appropriate wrapper class.
416 *
417 * @param <E> the element type
418 * @param array the array over which to iterate
419 * @param start the index to start iterating at
420 * @param end the index to finish iterating at
421 * @return a list iterator over part of the array
422 * @throws IllegalArgumentException if the array is not an array or end is before start
423 * @throws IndexOutOfBoundsException if array bounds are invalid
424 * @throws NullPointerException if array is null
425 */
426 public static <E> ResettableListIterator<E> arrayListIterator(final Object array, final int start, final int end) {
427 return new ArrayListIterator<E>(array, start, end);
428 }
429
430 // Unmodifiable
431 //-----------------------------------------------------------------------
432 /**
433 * Gets an immutable version of an {@link Iterator}. The returned object
434 * will always throw an {@link UnsupportedOperationException} for
435 * the {@link Iterator#remove} method.
436 *
437 * @param <E> the element type
438 * @param iterator the iterator to make immutable
439 * @return an immutable version of the iterator
440 */
441 public static <E> Iterator<E> unmodifiableIterator(final Iterator<E> iterator) {
442 return UnmodifiableIterator.unmodifiableIterator(iterator);
443 }
444
445 /**
446 * Gets an immutable version of a {@link ListIterator}. The returned object
447 * will always throw an {@link UnsupportedOperationException} for
448 * the {@link Iterator#remove}, {@link ListIterator#add} and
449 * {@link ListIterator#set} methods.
450 *
451 * @param <E> the element type
452 * @param listIterator the iterator to make immutable
453 * @return an immutable version of the iterator
454 */
455 public static <E> ListIterator<E> unmodifiableListIterator(final ListIterator<E> listIterator) {
456 return UnmodifiableListIterator.umodifiableListIterator(listIterator);
457 }
458
459 /**
460 * Gets an immutable version of a {@link MapIterator}. The returned object
461 * will always throw an {@link UnsupportedOperationException} for
462 * the {@link Iterator#remove}, {@link MapIterator#setValue(Object)} methods.
463 *
464 * @param <K> the key type
465 * @param <V> the value type
466 * @param mapIterator the iterator to make immutable
467 * @return an immutable version of the iterator
468 */
469 public static <K, V> MapIterator<K, V> unmodifiableMapIterator(final MapIterator<K, V> mapIterator) {
470 return UnmodifiableMapIterator.unmodifiableMapIterator(mapIterator);
471 }
472
473 // Chained
474 //-----------------------------------------------------------------------
475 /**
476 * Gets an iterator that iterates through two {@link Iterator}s
477 * one after another.
478 *
479 * @param <E> the element type
480 * @param iterator1 the first iterator to use, not null
481 * @param iterator2 the second iterator to use, not null
482 * @return a combination iterator over the iterators
483 * @throws NullPointerException if either iterator is null
484 */
485 public static <E> Iterator<E> chainedIterator(final Iterator<? extends E> iterator1,
486 final Iterator<? extends E> iterator2) {
487 return new IteratorChain<E>(iterator1, iterator2);
488 }
489
490 /**
491 * Gets an iterator that iterates through an array of {@link Iterator}s
492 * one after another.
493 *
494 * @param <E> the element type
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
498 */
499 public static <E> Iterator<E> chainedIterator(final Iterator<? extends E>[] iterators) {
500 return new IteratorChain<E>(iterators);
501 }
502
503 /**
504 * Gets an iterator that iterates through a collections of {@link Iterator}s
505 * one after another.
506 *
507 * @param <E> the element type
508 * @param iterators the iterators to use, not null or empty or contain nulls
509 * @return a combination iterator over the iterators
510 * @throws NullPointerException if iterators collection is null or contains a null
511 * @throws ClassCastException if the iterators collection contains the wrong object type
512 */
513 public static <E> Iterator<E> chainedIterator(final Collection<Iterator<? extends E>> iterators) {
514 return new IteratorChain<E>(iterators);
515 }
516
517 // Collated
518 //-----------------------------------------------------------------------
519 /**
520 * Gets an iterator that provides an ordered iteration over the elements
521 * contained in a collection of ordered {@link Iterator}s.
522 * <p>
523 * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
524 * the {@link Iterator#next()} method will return the lesser of
525 * <code>A.next()</code> and <code>B.next()</code>.
526 * <p>
527 * The comparator is optional. If null is specified then natural order is used.
528 *
529 * @param <E> the element type
530 * @param comparator the comparator to use, may be null for natural order
531 * @param iterator1 the first iterators to use, not null
532 * @param iterator2 the first iterators to use, not null
533 * @return a combination iterator over the iterators
534 * @throws NullPointerException if either iterator is null
535 */
536 public static <E> Iterator<E> collatedIterator(final Comparator<? super E> comparator,
537 final Iterator<? extends E> iterator1,
538 final Iterator<? extends E> iterator2) {
539 return new CollatingIterator<E>(comparator, iterator1, iterator2);
540 }
541
542 /**
543 * Gets an iterator that provides an ordered iteration over the elements
544 * contained in an array of {@link Iterator}s.
545 * <p>
546 * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
547 * the {@link Iterator#next()} method will return the lesser of
548 * <code>A.next()</code> and <code>B.next()</code> and so on.
549 * <p>
550 * The comparator is optional. If null is specified then natural order is used.
551 *
552 * @param <E> the element type
553 * @param comparator the comparator to use, may be null for natural order
554 * @param iterators the iterators to use, not null or empty or contain nulls
555 * @return a combination iterator over the iterators
556 * @throws NullPointerException if iterators array is null or contains a null value
557 */
558 public static <E> Iterator<E> collatedIterator(final Comparator<? super E> comparator,
559 final Iterator<? extends E>[] iterators) {
560 return new CollatingIterator<E>(comparator, iterators);
561 }
562
563 /**
564 * Gets an iterator that provides an ordered iteration over the elements
565 * contained in a collection of {@link Iterator}s.
566 * <p>
567 * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
568 * the {@link Iterator#next()} method will return the lesser of
569 * <code>A.next()</code> and <code>B.next()</code> and so on.
570 * <p>
571 * The comparator is optional. If null is specified then natural order is used.
572 *
573 * @param <E> the element type
574 * @param comparator the comparator to use, may be null for natural order
575 * @param iterators the iterators to use, not null or empty or contain nulls
576 * @return a combination iterator over the iterators
577 * @throws NullPointerException if iterators collection is null or contains a null
578 * @throws ClassCastException if the iterators collection contains the wrong object type
579 */
580 public static <E> Iterator<E> collatedIterator(final Comparator<? super E> comparator,
581 final Collection<Iterator<? extends E>> iterators) {
582 return new CollatingIterator<E>(comparator, iterators);
583 }
584
585 // Object Graph
586 //-----------------------------------------------------------------------
587 /**
588 * Gets an iterator that operates over an object graph.
589 * <p>
590 * This iterator can extract multiple objects from a complex tree-like object graph.
591 * The iteration starts from a single root object.
592 * It uses a <code>Transformer</code> to extract the iterators and elements.
593 * Its main benefit is that no intermediate <code>List</code> is created.
594 * <p>
595 * For example, consider an object graph:
596 * <pre>
597 * |- Branch -- Leaf
598 * | \- Leaf
599 * |- Tree | /- Leaf
600 * | |- Branch -- Leaf
601 * Forest | \- Leaf
602 * | |- Branch -- Leaf
603 * | | \- Leaf
604 * |- Tree | /- Leaf
605 * |- Branch -- Leaf
606 * |- Branch -- Leaf</pre>
607 * The following <code>Transformer</code>, used in this class, will extract all
608 * the Leaf objects without creating a combined intermediate list:
609 * <pre>
610 * public Object transform(Object input) {
611 * if (input instanceof Forest) {
612 * return ((Forest) input).treeIterator();
613 * }
614 * if (input instanceof Tree) {
615 * return ((Tree) input).branchIterator();
616 * }
617 * if (input instanceof Branch) {
618 * return ((Branch) input).leafIterator();
619 * }
620 * if (input instanceof Leaf) {
621 * return input;
622 * }
623 * throw new ClassCastException();
624 * }</pre>
625 * <p>
626 * Internally, iteration starts from the root object. When next is called,
627 * the transformer is called to examine the object. The transformer will return
628 * either an iterator or an object. If the object is an Iterator, the next element
629 * from that iterator is obtained and the process repeats. If the element is an object
630 * it is returned.
631 * <p>
632 * Under many circumstances, linking Iterators together in this manner is
633 * more efficient (and convenient) than using nested for loops to extract a list.
634 *
635 * @param <E> the element type
636 * @param root the root object to start iterating from, null results in an empty iterator
637 * @param transformer the transformer to use, see above, null uses no effect transformer
638 * @return a new object graph iterator
639 * @since 3.1
640 */
641 public static <E> Iterator<E> objectGraphIterator(final E root,
642 final Transformer<? super E, ? extends E> transformer) {
643 return new ObjectGraphIterator<E>(root, transformer);
644 }
645
646 // Transformed
647 //-----------------------------------------------------------------------
648 /**
649 * Gets an iterator that transforms the elements of another iterator.
650 * <p>
651 * The transformation occurs during the next() method and the underlying
652 * iterator is unaffected by the transformation.
653 *
654 * @param <I> the input type
655 * @param <O> the output type
656 * @param iterator the iterator to use, not null
657 * @param transform the transform to use, not null
658 * @return a new transforming iterator
659 * @throws NullPointerException if either parameter is null
660 */
661 public static <I, O> Iterator<O> transformedIterator(final Iterator<? extends I> iterator,
662 final Transformer<? super I, ? extends O> transform) {
663
664 if (iterator == null) {
665 throw new NullPointerException("Iterator must not be null");
666 }
667 if (transform == null) {
668 throw new NullPointerException("Transformer must not be null");
669 }
670 return new TransformIterator<I, O>(iterator, transform);
671 }
672
673 // Filtered
674 //-----------------------------------------------------------------------
675 /**
676 * Gets an iterator that filters another iterator.
677 * <p>
678 * The returned iterator will only return objects that match the specified
679 * filtering predicate.
680 *
681 * @param <E> the element type
682 * @param iterator the iterator to use, not null
683 * @param predicate the predicate to use as a filter, not null
684 * @return a new filtered iterator
685 * @throws NullPointerException if either parameter is null
686 */
687 public static <E> Iterator<E> filteredIterator(final Iterator<? extends E> iterator,
688 final Predicate<? super E> predicate) {
689 if (iterator == null) {
690 throw new NullPointerException("Iterator must not be null");
691 }
692 if (predicate == null) {
693 throw new NullPointerException("Predicate must not be null");
694 }
695 return new FilterIterator<E>(iterator, predicate);
696 }
697
698 /**
699 * Gets a list iterator that filters another list iterator.
700 * <p>
701 * The returned iterator will only return objects that match the specified
702 * filtering predicate.
703 *
704 * @param <E> the element type
705 * @param listIterator the list iterator to use, not null
706 * @param predicate the predicate to use as a filter, not null
707 * @return a new filtered iterator
708 * @throws NullPointerException if either parameter is null
709 */
710 public static <E> ListIterator<E> filteredListIterator(final ListIterator<? extends E> listIterator,
711 final Predicate<? super E> predicate) {
712
713 if (listIterator == null) {
714 throw new NullPointerException("ListIterator must not be null");
715 }
716 if (predicate == null) {
717 throw new NullPointerException("Predicate must not be null");
718 }
719 return new FilterListIterator<E>(listIterator, predicate);
720 }
721
722 // Looping
723 //-----------------------------------------------------------------------
724 /**
725 * Gets an iterator that loops continuously over the supplied collection.
726 * <p>
727 * The iterator will only stop looping if the remove method is called
728 * enough times to empty the collection, or if the collection is empty
729 * to start with.
730 *
731 * @param <E> the element type
732 * @param coll the collection to iterate over, not null
733 * @return a new looping iterator
734 * @throws NullPointerException if the collection is null
735 */
736 public static <E> ResettableIterator<E> loopingIterator(final Collection<? extends E> coll) {
737 if (coll == null) {
738 throw new NullPointerException("Collection must not be null");
739 }
740 return new LoopingIterator<E>(coll);
741 }
742
743 /**
744 * Gets an iterator that loops continuously over the supplied list.
745 * <p>
746 * The iterator will only stop looping if the remove method is called
747 * enough times to empty the list, or if the list is empty to start with.
748 *
749 * @param <E> the element type
750 * @param list the list to iterate over, not null
751 * @return a new looping iterator
752 * @throws NullPointerException if the list is null
753 * @since 3.2
754 */
755 public static <E> ResettableListIterator<E> loopingListIterator(final List<E> list) {
756 if (list == null) {
757 throw new NullPointerException("List must not be null");
758 }
759 return new LoopingListIterator<E>(list);
760 }
761
762 // org.w3c.dom.NodeList iterators
763 //-----------------------------------------------------------------------
764 /**
765 * Gets an {@link Iterator} that wraps the specified {@link NodeList}.
766 * The returned {@link Iterator} can be used for a single iteration.
767 *
768 * @param nodeList the node list to use, not null
769 * @return a new, single use {@link Iterator}
770 * @throws NullPointerException if nodeList is null
771 * @since 4.0
772 */
773 public static NodeListIterator nodeListIterator(final NodeList nodeList) {
774 if (nodeList == null) {
775 throw new NullPointerException("NodeList must not be null");
776 }
777 return new NodeListIterator(nodeList);
778 }
779
780 /**
781 * Gets an {@link Iterator} that wraps the specified node's childNodes.
782 * The returned {@link Iterator} can be used for a single iteration.
783 * <p>
784 * Convenience method, allows easy iteration over NodeLists:
785 * <pre>
786 * Iterator<Node> iterator = IteratorUtils.nodeListIterator(node);
787 * for(Node childNode : IteratorUtils.asIterable(iterator)) {
788 * ...
789 * }
790 * </pre>
791 *
792 * @param node the node to use, not null
793 * @return a new, single use {@link Iterator}
794 * @throws NullPointerException if node is null
795 * @since 4.0
796 */
797 public static NodeListIterator nodeListIterator(final Node node) {
798 if (node == null) {
799 throw new NullPointerException("Node must not be null");
800 }
801 return new NodeListIterator(node);
802 }
803
804 // Views
805 //-----------------------------------------------------------------------
806 /**
807 * Gets an iterator that provides an iterator view of the given enumeration.
808 *
809 * @param <E> the element type
810 * @param enumeration the enumeration to use
811 * @return a new iterator
812 */
813 public static <E> Iterator<E> asIterator(final Enumeration<? extends E> enumeration) {
814 if (enumeration == null) {
815 throw new NullPointerException("Enumeration must not be null");
816 }
817 return new EnumerationIterator<E>(enumeration);
818 }
819
820 /**
821 * Gets an iterator that provides an iterator view of the given enumeration
822 * that will remove elements from the specified collection.
823 *
824 * @param <E> the element type
825 * @param enumeration the enumeration to use
826 * @param removeCollection the collection to remove elements from
827 * @return a new iterator
828 */
829 public static <E> Iterator<E> asIterator(final Enumeration<? extends E> enumeration,
830 final Collection<? super E> removeCollection) {
831 if (enumeration == null) {
832 throw new NullPointerException("Enumeration must not be null");
833 }
834 if (removeCollection == null) {
835 throw new NullPointerException("Collection must not be null");
836 }
837 return new EnumerationIterator<E>(enumeration, removeCollection);
838 }
839
840 /**
841 * Gets an enumeration that wraps an iterator.
842 *
843 * @param <E> the element type
844 * @param iterator the iterator to use, not null
845 * @return a new enumeration
846 * @throws NullPointerException if iterator is null
847 */
848 public static <E> Enumeration<E> asEnumeration(final Iterator<? extends E> iterator) {
849 if (iterator == null) {
850 throw new NullPointerException("Iterator must not be null");
851 }
852 return new IteratorEnumeration<E>(iterator);
853 }
854
855 /**
856 * Gets an {@link Iterable} that wraps an iterator. The returned {@link Iterable} can be
857 * used for a single iteration.
858 *
859 * @param <E> the element type
860 * @param iterator the iterator to use, not null
861 * @return a new, single use {@link Iterable}
862 * @throws NullPointerException if iterator is null
863 */
864 public static <E> Iterable<E> asIterable(final Iterator<? extends E> iterator) {
865 if (iterator == null) {
866 throw new NullPointerException("Iterator must not be null");
867 }
868 return new IteratorIterable<E>(iterator, false);
869 }
870
871
872 /**
873 * Gets an iterable that wraps an iterator. The returned iterable can be
874 * used for multiple iterations.
875 *
876 * @param <E> the element type
877 * @param iterator the iterator to use, not null
878 * @return a new, multiple use iterable
879 * @throws NullPointerException if iterator is null
880 */
881 public static <E> Iterable<E> asMultipleUseIterable(final Iterator<? extends E> iterator) {
882 if (iterator == null) {
883 throw new NullPointerException("Iterator must not be null");
884 }
885 return new IteratorIterable<E>(iterator, true);
886 }
887
888 /**
889 * Gets a list iterator based on a simple iterator.
890 * <p>
891 * As the wrapped Iterator is traversed, a LinkedList of its values is
892 * cached, permitting all required operations of ListIterator.
893 *
894 * @param <E> the element type
895 * @param iterator the iterator to use, not null
896 * @return a new iterator
897 * @throws NullPointerException if iterator parameter is null
898 */
899 public static <E> ListIterator<E> toListIterator(final Iterator<? extends E> iterator) {
900 if (iterator == null) {
901 throw new NullPointerException("Iterator must not be null");
902 }
903 return new ListIteratorWrapper<E>(iterator);
904 }
905
906 /**
907 * Gets an array based on an iterator.
908 * <p>
909 * As the wrapped Iterator is traversed, an ArrayList of its values is
910 * created. At the end, this is converted to an array.
911 *
912 * @param iterator the iterator to use, not null
913 * @return an array of the iterator contents
914 * @throws NullPointerException if iterator parameter is null
915 */
916 public static Object[] toArray(final Iterator<?> iterator) {
917 if (iterator == null) {
918 throw new NullPointerException("Iterator must not be null");
919 }
920 final List<?> list = toList(iterator, 100);
921 return list.toArray();
922 }
923
924 /**
925 * Gets an array based on an iterator.
926 * <p>
927 * As the wrapped Iterator is traversed, an ArrayList of its values is
928 * created. At the end, this is converted to an array.
929 *
930 * @param <E> the element type
931 * @param iterator the iterator to use, not null
932 * @param arrayClass the class of array to create
933 * @return an array of the iterator contents
934 * @throws NullPointerException if iterator parameter or arrayClass is null
935 * @throws ClassCastException if the arrayClass is invalid
936 */
937 public static <E> E[] toArray(final Iterator<? extends E> iterator, final Class<E> arrayClass) {
938 if (iterator == null) {
939 throw new NullPointerException("Iterator must not be null");
940 }
941 if (arrayClass == null) {
942 throw new NullPointerException("Array class must not be null");
943 }
944 final List<E> list = toList(iterator, 100);
945 @SuppressWarnings("unchecked") // as per Javadoc, will throw CCE if class is wrong
946 final E[] array = (E[]) Array.newInstance(arrayClass, list.size());
947 return list.toArray(array);
948 }
949
950 /**
951 * Gets a list based on an iterator.
952 * <p>
953 * As the wrapped Iterator is traversed, an ArrayList of its values is
954 * created. At the end, the list is returned.
955 *
956 * @param <E> the element type
957 * @param iterator the iterator to use, not null
958 * @return a list of the iterator contents
959 * @throws NullPointerException if iterator parameter is null
960 */
961 public static <E> List<E> toList(final Iterator<? extends E> iterator) {
962 return toList(iterator, 10);
963 }
964
965 /**
966 * Gets a list based on an iterator.
967 * <p>
968 * As the wrapped Iterator is traversed, an ArrayList of its values is
969 * created. At the end, the list is returned.
970 *
971 * @param <E> the element type
972 * @param iterator the iterator to use, not null
973 * @param estimatedSize the initial size of the ArrayList
974 * @return a list of the iterator contents
975 * @throws NullPointerException if iterator parameter is null
976 * @throws IllegalArgumentException if the size is less than 1
977 */
978 public static <E> List<E> toList(final Iterator<? extends E> iterator, final int estimatedSize) {
979 if (iterator == null) {
980 throw new NullPointerException("Iterator must not be null");
981 }
982 if (estimatedSize < 1) {
983 throw new IllegalArgumentException("Estimated size must be greater than 0");
984 }
985 final List<E> list = new ArrayList<E>(estimatedSize);
986 while (iterator.hasNext()) {
987 list.add(iterator.next());
988 }
989 return list;
990 }
991
992 /**
993 * Gets a suitable Iterator for the given object.
994 * <p>
995 * This method can handle objects as follows
996 * <ul>
997 * <li>null - empty iterator
998 * <li>Iterator - returned directly
999 * <li>Enumeration - wrapped
1000 * <li>Collection - iterator from collection returned
1001 * <li>Map - values iterator returned
1002 * <li>Dictionary - values (elements) enumeration returned as iterator
1003 * <li>array - iterator over array returned
1004 * <li>object with iterator() public method accessed by reflection
1005 * <li>object - singleton iterator
1006 * <li>NodeList - iterator over the list
1007 * <li>Node - iterator over the child nodes
1008 * </ul>
1009 *
1010 * @param obj the object to convert to an iterator
1011 * @return a suitable iterator, never null
1012 */
1013 public static Iterator<?> getIterator(final Object obj) {
1014 if (obj == null) {
1015 return emptyIterator();
1016 }
1017 if (obj instanceof Iterator) {
1018 return (Iterator<?>) obj;
1019 }
1020 if (obj instanceof Collection) {
1021 return ((Collection<?>) obj).iterator();
1022 }
1023 if (obj instanceof Object[]) {
1024 return new ObjectArrayIterator<Object>((Object[]) obj);
1025 }
1026 if (obj instanceof Enumeration) {
1027 return new EnumerationIterator<Object>((Enumeration<?>) obj);
1028 }
1029 if (obj instanceof Map) {
1030 return ((Map<?, ?>) obj).values().iterator();
1031 }
1032 if (obj instanceof NodeList) {
1033 return new NodeListIterator((NodeList) obj);
1034 }
1035 if (obj instanceof Node) {
1036 return new NodeListIterator((Node) obj);
1037 }
1038 if (obj instanceof Dictionary) {
1039 return new EnumerationIterator<Object>(((Dictionary<?, ?>) obj).elements());
1040 } else if (obj.getClass().isArray()) {
1041 return new ArrayIterator<Object>(obj);
1042 }
1043 try {
1044 final Method method = obj.getClass().getMethod("iterator", (Class[]) null);
1045 if (Iterator.class.isAssignableFrom(method.getReturnType())) {
1046 final Iterator<?> it = (Iterator<?>) method.invoke(obj, (Object[]) null);
1047 if (it != null) {
1048 return it;
1049 }
1050 }
1051 } catch (final RuntimeException e) {
1052 // ignore
1053 } catch (final NoSuchMethodException e) {
1054 // ignore
1055 } catch (final IllegalAccessException e) {
1056 // ignore
1057 } catch (final InvocationTargetException e) {
1058 // ignore
1059 }
1060 return singletonIterator(obj);
1061 }
1062
1063 }