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 */
017 package org.apache.commons.collections;
018
019 import java.lang.reflect.Array;
020 import java.lang.reflect.Method;
021 import java.util.ArrayList;
022 import java.util.Collection;
023 import java.util.Comparator;
024 import java.util.Dictionary;
025 import java.util.Enumeration;
026 import java.util.Iterator;
027 import java.util.List;
028 import java.util.ListIterator;
029 import java.util.Map;
030
031 import org.apache.commons.collections.iterators.ArrayIterator;
032 import org.apache.commons.collections.iterators.ArrayListIterator;
033 import org.apache.commons.collections.iterators.CollatingIterator;
034 import org.apache.commons.collections.iterators.EmptyIterator;
035 import org.apache.commons.collections.iterators.EmptyListIterator;
036 import org.apache.commons.collections.iterators.EmptyMapIterator;
037 import org.apache.commons.collections.iterators.EmptyOrderedIterator;
038 import org.apache.commons.collections.iterators.EmptyOrderedMapIterator;
039 import org.apache.commons.collections.iterators.EnumerationIterator;
040 import org.apache.commons.collections.iterators.FilterIterator;
041 import org.apache.commons.collections.iterators.FilterListIterator;
042 import org.apache.commons.collections.iterators.IteratorChain;
043 import org.apache.commons.collections.iterators.IteratorEnumeration;
044 import org.apache.commons.collections.iterators.ListIteratorWrapper;
045 import org.apache.commons.collections.iterators.LoopingIterator;
046 import org.apache.commons.collections.iterators.LoopingListIterator;
047 import org.apache.commons.collections.iterators.ObjectArrayIterator;
048 import org.apache.commons.collections.iterators.ObjectArrayListIterator;
049 import org.apache.commons.collections.iterators.ObjectGraphIterator;
050 import org.apache.commons.collections.iterators.SingletonIterator;
051 import org.apache.commons.collections.iterators.SingletonListIterator;
052 import org.apache.commons.collections.iterators.TransformIterator;
053 import org.apache.commons.collections.iterators.UnmodifiableIterator;
054 import org.apache.commons.collections.iterators.UnmodifiableListIterator;
055 import org.apache.commons.collections.iterators.UnmodifiableMapIterator;
056
057 /**
058 * Provides static utility methods and decorators for {@link Iterator}
059 * instances. The implementations are provided in the iterators subpackage.
060 * <p>
061 * WARNING: Due to human error certain binary incompatabilities were introduced
062 * between Commons Collections 2.1 and 3.0. The class remained source and test
063 * compatible, so if you can recompile all your classes and dependencies
064 * everything is OK. Those methods which are binary incompatible are marked as
065 * such, together with alternate solutions that are binary compatible
066 * against versions 2.1.1 and 3.1.
067 *
068 * @since Commons Collections 2.1
069 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
070 *
071 * @author Stephen Colebourne
072 * @author Phil Steitz
073 */
074 public 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 * <p>
081 * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
082 * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
083 */
084 public static final ResettableIterator EMPTY_ITERATOR = EmptyIterator.RESETTABLE_INSTANCE;
085 /**
086 * A list iterator over no elements.
087 * <p>
088 * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
089 * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
090 */
091 public static final ResettableListIterator EMPTY_LIST_ITERATOR = EmptyListIterator.RESETTABLE_INSTANCE;
092 /**
093 * An ordered iterator over no elements.
094 */
095 public static final OrderedIterator EMPTY_ORDERED_ITERATOR = EmptyOrderedIterator.INSTANCE;
096 /**
097 * A map iterator over no elements.
098 */
099 public static final MapIterator EMPTY_MAP_ITERATOR = EmptyMapIterator.INSTANCE;
100 /**
101 * An ordered map iterator over no elements.
102 */
103 public static final OrderedMapIterator EMPTY_ORDERED_MAP_ITERATOR = EmptyOrderedMapIterator.INSTANCE;
104
105 /**
106 * IteratorUtils is not normally instantiated.
107 */
108 public IteratorUtils() {
109 }
110
111 // Empty
112 //-----------------------------------------------------------------------
113 /**
114 * Gets an empty iterator.
115 * <p>
116 * This iterator is a valid iterator object that will iterate over
117 * nothing.
118 * <p>
119 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
120 * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
121 *
122 * @return an iterator over nothing
123 */
124 public static ResettableIterator emptyIterator() {
125 return EMPTY_ITERATOR;
126 }
127
128 /**
129 * Gets an empty list iterator.
130 * <p>
131 * This iterator is a valid list iterator object that will iterate
132 * over nothing.
133 * <p>
134 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
135 * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
136 *
137 * @return a list iterator over nothing
138 */
139 public static ResettableListIterator emptyListIterator() {
140 return EMPTY_LIST_ITERATOR;
141 }
142
143 /**
144 * Gets an empty ordered iterator.
145 * <p>
146 * This iterator is a valid iterator object that will iterate
147 * over nothing.
148 *
149 * @return an ordered iterator over nothing
150 */
151 public static OrderedIterator emptyOrderedIterator() {
152 return EMPTY_ORDERED_ITERATOR;
153 }
154
155 /**
156 * Gets an empty map iterator.
157 * <p>
158 * This iterator is a valid map iterator object that will iterate
159 * over nothing.
160 *
161 * @return a map iterator over nothing
162 */
163 public static MapIterator emptyMapIterator() {
164 return EMPTY_MAP_ITERATOR;
165 }
166
167 /**
168 * Gets an empty ordered map iterator.
169 * <p>
170 * This iterator is a valid map iterator object that will iterate
171 * over nothing.
172 *
173 * @return a map iterator over nothing
174 */
175 public static OrderedMapIterator emptyOrderedMapIterator() {
176 return EMPTY_ORDERED_MAP_ITERATOR;
177 }
178
179 // Singleton
180 //-----------------------------------------------------------------------
181 /**
182 * Gets a singleton iterator.
183 * <p>
184 * This iterator is a valid iterator object that will iterate over
185 * the specified object.
186 * <p>
187 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
188 * Use <code>new SingletonIterator(object)</code> for compatability.
189 *
190 * @param object the single object over which to iterate
191 * @return a singleton iterator over the object
192 */
193 public static ResettableIterator singletonIterator(Object object) {
194 return new SingletonIterator(object);
195 }
196
197 /**
198 * Gets a singleton list iterator.
199 * <p>
200 * This iterator is a valid list iterator object that will iterate over
201 * the specified object.
202 *
203 * @param object the single object over which to iterate
204 * @return a singleton list iterator over the object
205 */
206 public static ListIterator singletonListIterator(Object object) {
207 return new SingletonListIterator(object);
208 }
209
210 // Arrays
211 //-----------------------------------------------------------------------
212 /**
213 * Gets an iterator over an object array.
214 * <p>
215 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
216 * Use <code>new ArrayIterator(array)</code> for compatability.
217 *
218 * @param array the array over which to iterate
219 * @return an iterator over the array
220 * @throws NullPointerException if array is null
221 */
222 public static ResettableIterator arrayIterator(Object[] array) {
223 return new ObjectArrayIterator(array);
224 }
225
226 /**
227 * Gets an iterator over an object or primitive array.
228 * <p>
229 * This method will handle primitive arrays as well as object arrays.
230 * The primitives will be wrapped in the appropriate wrapper class.
231 *
232 * @param array the array over which to iterate
233 * @return an iterator over the array
234 * @throws IllegalArgumentException if the array is not an array
235 * @throws NullPointerException if array is null
236 */
237 public static ResettableIterator arrayIterator(Object array) {
238 return new ArrayIterator(array);
239 }
240
241 /**
242 * Gets an iterator over the end part of an object array.
243 * <p>
244 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
245 * Use <code>new ArrayIterator(array,start)</code> for compatability.
246 *
247 * @param array the array over which to iterate
248 * @param start the index to start iterating at
249 * @return an iterator over part of the array
250 * @throws IndexOutOfBoundsException if start is less than zero or greater
251 * than the length of the array
252 * @throws NullPointerException if array is null
253 */
254 public static ResettableIterator arrayIterator(Object[] array, int start) {
255 return new ObjectArrayIterator(array, start);
256 }
257
258 /**
259 * Gets an iterator over the end part of an object or primitive array.
260 * <p>
261 * This method will handle primitive arrays as well as object arrays.
262 * The primitives will be wrapped in the appropriate wrapper class.
263 *
264 * @param array the array over which to iterate
265 * @param start the index to start iterating at
266 * @return an iterator over part of the array
267 * @throws IllegalArgumentException if the array is not an array
268 * @throws IndexOutOfBoundsException if start is less than zero or greater
269 * than the length of the array
270 * @throws NullPointerException if array is null
271 */
272 public static ResettableIterator arrayIterator(Object array, int start) {
273 return new ArrayIterator(array, start);
274 }
275
276 /**
277 * Gets an iterator over part of an object array.
278 * <p>
279 * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
280 * Use <code>new ArrayIterator(array,start,end)</code> for compatability.
281 *
282 * @param array the array over which to iterate
283 * @param start the index to start iterating at
284 * @param end the index to finish iterating at
285 * @return an iterator over part of the array
286 * @throws IndexOutOfBoundsException if array bounds are invalid
287 * @throws IllegalArgumentException if end is before start
288 * @throws NullPointerException if array is null
289 */
290 public static ResettableIterator arrayIterator(Object[] array, int start, int end) {
291 return new ObjectArrayIterator(array, start, end);
292 }
293
294 /**
295 * Gets an iterator over part of an object or primitive array.
296 * <p>
297 * This method will handle primitive arrays as well as object arrays.
298 * The primitives will be wrapped in the appropriate wrapper class.
299 *
300 * @param array the array over which to iterate
301 * @param start the index to start iterating at
302 * @param end the index to finish iterating at
303 * @return an iterator over part of the array
304 * @throws IllegalArgumentException if the array is not an array
305 * @throws IndexOutOfBoundsException if array bounds are invalid
306 * @throws IllegalArgumentException if end is before start
307 * @throws NullPointerException if array is null
308 */
309 public static ResettableIterator arrayIterator(Object array, int start, int end) {
310 return new ArrayIterator(array, start, end);
311 }
312
313 //-----------------------------------------------------------------------
314 /**
315 * Gets a list iterator over an object array.
316 *
317 * @param array the array over which to iterate
318 * @return a list iterator over the array
319 * @throws NullPointerException if array is null
320 */
321 public static ResettableListIterator arrayListIterator(Object[] array) {
322 return new ObjectArrayListIterator(array);
323 }
324
325 /**
326 * Gets a list iterator over an object or primitive array.
327 * <p>
328 * This method will handle primitive arrays as well as object arrays.
329 * The primitives will be wrapped in the appropriate wrapper class.
330 *
331 * @param array the array over which to iterate
332 * @return a list iterator over the array
333 * @throws IllegalArgumentException if the array is not an array
334 * @throws NullPointerException if array is null
335 */
336 public static ResettableListIterator arrayListIterator(Object array) {
337 return new ArrayListIterator(array);
338 }
339
340 /**
341 * Gets a list iterator over the end part of an object array.
342 *
343 * @param array the array over which to iterate
344 * @param start the index to start iterating at
345 * @return a list iterator over part of the array
346 * @throws IndexOutOfBoundsException if start is less than zero
347 * @throws NullPointerException if array is null
348 */
349 public static ResettableListIterator arrayListIterator(Object[] array, int start) {
350 return new ObjectArrayListIterator(array, start);
351 }
352
353 /**
354 * Gets a list iterator over the end part of an object or primitive array.
355 * <p>
356 * This method will handle primitive arrays as well as object arrays.
357 * The primitives will be wrapped in the appropriate wrapper class.
358 *
359 * @param array the array over which to iterate
360 * @param start the index to start iterating at
361 * @return a list iterator over part of the array
362 * @throws IllegalArgumentException if the array is not an array
363 * @throws IndexOutOfBoundsException if start is less than zero
364 * @throws NullPointerException if array is null
365 */
366 public static ResettableListIterator arrayListIterator(Object array, int start) {
367 return new ArrayListIterator(array, start);
368 }
369
370 /**
371 * Gets a list iterator over part of an object array.
372 *
373 * @param array the array over which to iterate
374 * @param start the index to start iterating at
375 * @param end the index to finish iterating at
376 * @return a list iterator over part of the array
377 * @throws IndexOutOfBoundsException if array bounds are invalid
378 * @throws IllegalArgumentException if end is before start
379 * @throws NullPointerException if array is null
380 */
381 public static ResettableListIterator arrayListIterator(Object[] array, int start, int end) {
382 return new ObjectArrayListIterator(array, start, end);
383 }
384
385 /**
386 * Gets a list iterator over part of an object or primitive array.
387 * <p>
388 * This method will handle primitive arrays as well as object arrays.
389 * The primitives will be wrapped in the appropriate wrapper class.
390 *
391 * @param array the array over which to iterate
392 * @param start the index to start iterating at
393 * @param end the index to finish iterating at
394 * @return a list iterator over part of the array
395 * @throws IllegalArgumentException if the array is not an array
396 * @throws IndexOutOfBoundsException if array bounds are invalid
397 * @throws IllegalArgumentException if end is before start
398 * @throws NullPointerException if array is null
399 */
400 public static ResettableListIterator arrayListIterator(Object array, int start, int end) {
401 return new ArrayListIterator(array, start, end);
402 }
403
404 // Unmodifiable
405 //-----------------------------------------------------------------------
406 /**
407 * Gets an immutable version of an {@link Iterator}. The returned object
408 * will always throw an {@link UnsupportedOperationException} for
409 * the {@link Iterator#remove} method.
410 *
411 * @param iterator the iterator to make immutable
412 * @return an immutable version of the iterator
413 */
414 public static Iterator unmodifiableIterator(Iterator iterator) {
415 return UnmodifiableIterator.decorate(iterator);
416 }
417
418 /**
419 * Gets an immutable version of a {@link ListIterator}. The returned object
420 * will always throw an {@link UnsupportedOperationException} for
421 * the {@link Iterator#remove}, {@link ListIterator#add} and
422 * {@link ListIterator#set} methods.
423 *
424 * @param listIterator the iterator to make immutable
425 * @return an immutable version of the iterator
426 */
427 public static ListIterator unmodifiableListIterator(ListIterator listIterator) {
428 return UnmodifiableListIterator.decorate(listIterator);
429 }
430
431 /**
432 * Gets an immutable version of a {@link MapIterator}. The returned object
433 * will always throw an {@link UnsupportedOperationException} for
434 * the {@link Iterator#remove}, {@link MapIterator#setValue(Object)} methods.
435 *
436 * @param mapIterator the iterator to make immutable
437 * @return an immutable version of the iterator
438 */
439 public static MapIterator unmodifiableMapIterator(MapIterator mapIterator) {
440 return UnmodifiableMapIterator.decorate(mapIterator);
441 }
442
443 // Chained
444 //-----------------------------------------------------------------------
445 /**
446 * Gets an iterator that iterates through two {@link Iterator}s
447 * one after another.
448 *
449 * @param iterator1 the first iterators to use, not null
450 * @param iterator2 the first iterators to use, not null
451 * @return a combination iterator over the iterators
452 * @throws NullPointerException if either iterator is null
453 */
454 public static Iterator chainedIterator(Iterator iterator1, Iterator iterator2) {
455 return new IteratorChain(iterator1, iterator2);
456 }
457
458 /**
459 * Gets an iterator that iterates through an array of {@link Iterator}s
460 * one after another.
461 *
462 * @param iterators the iterators to use, not null or empty or contain nulls
463 * @return a combination iterator over the iterators
464 * @throws NullPointerException if iterators array is null or contains a null
465 */
466 public static Iterator chainedIterator(Iterator[] iterators) {
467 return new IteratorChain(iterators);
468 }
469
470 /**
471 * Gets an iterator that iterates through a collections of {@link Iterator}s
472 * one after another.
473 *
474 * @param iterators the iterators to use, not null or empty or contain nulls
475 * @return a combination iterator over the iterators
476 * @throws NullPointerException if iterators collection is null or contains a null
477 * @throws ClassCastException if the iterators collection contains the wrong object type
478 */
479 public static Iterator chainedIterator(Collection iterators) {
480 return new IteratorChain(iterators);
481 }
482
483 // Collated
484 //-----------------------------------------------------------------------
485 /**
486 * Gets an iterator that provides an ordered iteration over the elements
487 * contained in a collection of ordered {@link Iterator}s.
488 * <p>
489 * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
490 * the {@link Iterator#next()} method will return the lesser of
491 * <code>A.next()</code> and <code>B.next()</code>.
492 * <p>
493 * The comparator is optional. If null is specified then natural order is used.
494 *
495 * @param comparator the comparator to use, may be null for natural order
496 * @param iterator1 the first iterators to use, not null
497 * @param iterator2 the first iterators to use, not null
498 * @return a combination iterator over the iterators
499 * @throws NullPointerException if either iterator is null
500 */
501 public static Iterator collatedIterator(Comparator comparator, Iterator iterator1, Iterator iterator2) {
502 return new CollatingIterator(comparator, iterator1, iterator2);
503 }
504
505 /**
506 * Gets an iterator that provides an ordered iteration over the elements
507 * contained in an array of {@link Iterator}s.
508 * <p>
509 * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
510 * the {@link Iterator#next()} method will return the lesser of
511 * <code>A.next()</code> and <code>B.next()</code> and so on.
512 * <p>
513 * The comparator is optional. If null is specified then natural order is used.
514 *
515 * @param comparator the comparator to use, may be null for natural order
516 * @param iterators the iterators to use, not null or empty or contain nulls
517 * @return a combination iterator over the iterators
518 * @throws NullPointerException if iterators array is null or contains a null
519 */
520 public static Iterator collatedIterator(Comparator comparator, Iterator[] iterators) {
521 return new CollatingIterator(comparator, iterators);
522 }
523
524 /**
525 * Gets an iterator that provides an ordered iteration over the elements
526 * contained in a collection of {@link Iterator}s.
527 * <p>
528 * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
529 * the {@link Iterator#next()} method will return the lesser of
530 * <code>A.next()</code> and <code>B.next()</code> and so on.
531 * <p>
532 * The comparator is optional. If null is specified then natural order is used.
533 *
534 * @param comparator the comparator to use, may be null for natural order
535 * @param iterators the iterators to use, not null or empty or contain nulls
536 * @return a combination iterator over the iterators
537 * @throws NullPointerException if iterators collection is null or contains a null
538 * @throws ClassCastException if the iterators collection contains the wrong object type
539 */
540 public static Iterator collatedIterator(Comparator comparator, Collection iterators) {
541 return new CollatingIterator(comparator, iterators);
542 }
543
544 // Object Graph
545 //-----------------------------------------------------------------------
546 /**
547 * Gets an iterator that operates over an object graph.
548 * <p>
549 * This iterator can extract multiple objects from a complex tree-like object graph.
550 * The iteration starts from a single root object.
551 * It uses a <code>Transformer</code> to extract the iterators and elements.
552 * Its main benefit is that no intermediate <code>List</code> is created.
553 * <p>
554 * For example, consider an object graph:
555 * <pre>
556 * |- Branch -- Leaf
557 * | \- Leaf
558 * |- Tree | /- Leaf
559 * | |- Branch -- Leaf
560 * Forest | \- Leaf
561 * | |- Branch -- Leaf
562 * | | \- Leaf
563 * |- Tree | /- Leaf
564 * |- Branch -- Leaf
565 * |- Branch -- Leaf</pre>
566 * The following <code>Transformer</code>, used in this class, will extract all
567 * the Leaf objects without creating a combined intermediate list:
568 * <pre>
569 * public Object transform(Object input) {
570 * if (input instanceof Forest) {
571 * return ((Forest) input).treeIterator();
572 * }
573 * if (input instanceof Tree) {
574 * return ((Tree) input).branchIterator();
575 * }
576 * if (input instanceof Branch) {
577 * return ((Branch) input).leafIterator();
578 * }
579 * if (input instanceof Leaf) {
580 * return input;
581 * }
582 * throw new ClassCastException();
583 * }</pre>
584 * <p>
585 * Internally, iteration starts from the root object. When next is called,
586 * the transformer is called to examine the object. The transformer will return
587 * either an iterator or an object. If the object is an Iterator, the next element
588 * from that iterator is obtained and the process repeats. If the element is an object
589 * it is returned.
590 * <p>
591 * Under many circumstances, linking Iterators together in this manner is
592 * more efficient (and convenient) than using nested for loops to extract a list.
593 *
594 * @param root the root object to start iterating from, null results in an empty iterator
595 * @param transformer the transformer to use, see above, null uses no effect transformer
596 * @return a new object graph iterator
597 * @since Commons Collections 3.1
598 */
599 public static Iterator objectGraphIterator(Object root, Transformer transformer) {
600 return new ObjectGraphIterator(root, transformer);
601 }
602
603 // Transformed
604 //-----------------------------------------------------------------------
605 /**
606 * Gets an iterator that transforms the elements of another iterator.
607 * <p>
608 * The transformation occurs during the next() method and the underlying
609 * iterator is unaffected by the transformation.
610 *
611 * @param iterator the iterator to use, not null
612 * @param transform the transform to use, not null
613 * @return a new transforming iterator
614 * @throws NullPointerException if either parameter is null
615 */
616 public static Iterator transformedIterator(Iterator iterator, Transformer transform) {
617 if (iterator == null) {
618 throw new NullPointerException("Iterator must not be null");
619 }
620 if (transform == null) {
621 throw new NullPointerException("Transformer must not be null");
622 }
623 return new TransformIterator(iterator, transform);
624 }
625
626 // Filtered
627 //-----------------------------------------------------------------------
628 /**
629 * Gets an iterator that filters another iterator.
630 * <p>
631 * The returned iterator will only return objects that match the specified
632 * filtering predicate.
633 *
634 * @param iterator the iterator to use, not null
635 * @param predicate the predicate to use as a filter, not null
636 * @return a new filtered iterator
637 * @throws NullPointerException if either parameter is null
638 */
639 public static Iterator filteredIterator(Iterator iterator, Predicate predicate) {
640 if (iterator == null) {
641 throw new NullPointerException("Iterator must not be null");
642 }
643 if (predicate == null) {
644 throw new NullPointerException("Predicate must not be null");
645 }
646 return new FilterIterator(iterator, predicate);
647 }
648
649 /**
650 * Gets a list iterator that filters another list iterator.
651 * <p>
652 * The returned iterator will only return objects that match the specified
653 * filtering predicate.
654 *
655 * @param listIterator the list iterator to use, not null
656 * @param predicate the predicate to use as a filter, not null
657 * @return a new filtered iterator
658 * @throws NullPointerException if either parameter is null
659 */
660 public static ListIterator filteredListIterator(ListIterator listIterator, Predicate predicate) {
661 if (listIterator == null) {
662 throw new NullPointerException("ListIterator must not be null");
663 }
664 if (predicate == null) {
665 throw new NullPointerException("Predicate must not be null");
666 }
667 return new FilterListIterator(listIterator, predicate);
668 }
669
670 // Looping
671 //-----------------------------------------------------------------------
672 /**
673 * Gets an iterator that loops continuously over the supplied collection.
674 * <p>
675 * The iterator will only stop looping if the remove method is called
676 * enough times to empty the collection, or if the collection is empty
677 * to start with.
678 *
679 * @param coll the collection to iterate over, not null
680 * @return a new looping iterator
681 * @throws NullPointerException if the collection is null
682 */
683 public static ResettableIterator loopingIterator(Collection coll) {
684 if (coll == null) {
685 throw new NullPointerException("Collection must not be null");
686 }
687 return new LoopingIterator(coll);
688 }
689
690 /**
691 * Gets an iterator that loops continuously over the supplied list.
692 * <p>
693 * The iterator will only stop looping if the remove method is called
694 * enough times to empty the list, or if the list is empty to start with.
695 *
696 * @param list the list to iterate over, not null
697 * @return a new looping iterator
698 * @throws NullPointerException if the list is null
699 * @since Commons Collections 3.2
700 */
701 public static ResettableListIterator loopingListIterator(List list) {
702 if (list == null) {
703 throw new NullPointerException("List must not be null");
704 }
705 return new LoopingListIterator(list);
706 }
707
708 // Views
709 //-----------------------------------------------------------------------
710 /**
711 * Gets an iterator that provides an iterator view of the given enumeration.
712 *
713 * @param enumeration the enumeration to use
714 * @return a new iterator
715 */
716 public static Iterator asIterator(Enumeration enumeration) {
717 if (enumeration == null) {
718 throw new NullPointerException("Enumeration must not be null");
719 }
720 return new EnumerationIterator(enumeration);
721 }
722
723 /**
724 * Gets an iterator that provides an iterator view of the given enumeration
725 * that will remove elements from the specified collection.
726 *
727 * @param enumeration the enumeration to use
728 * @param removeCollection the collection to remove elements from
729 * @return a new iterator
730 */
731 public static Iterator asIterator(Enumeration enumeration, Collection removeCollection) {
732 if (enumeration == null) {
733 throw new NullPointerException("Enumeration must not be null");
734 }
735 if (removeCollection == null) {
736 throw new NullPointerException("Collection must not be null");
737 }
738 return new EnumerationIterator(enumeration, removeCollection);
739 }
740
741 /**
742 * Gets an enumeration that wraps an iterator.
743 *
744 * @param iterator the iterator to use, not null
745 * @return a new enumeration
746 * @throws NullPointerException if iterator is null
747 */
748 public static Enumeration asEnumeration(Iterator iterator) {
749 if (iterator == null) {
750 throw new NullPointerException("Iterator must not be null");
751 }
752 return new IteratorEnumeration(iterator);
753 }
754
755 /**
756 * Gets a list iterator based on a simple iterator.
757 * <p>
758 * As the wrapped Iterator is traversed, a LinkedList of its values is
759 * cached, permitting all required operations of ListIterator.
760 *
761 * @param iterator the iterator to use, not null
762 * @return a new iterator
763 * @throws NullPointerException if iterator parameter is null
764 */
765 public static ListIterator toListIterator(Iterator iterator) {
766 if (iterator == null) {
767 throw new NullPointerException("Iterator must not be null");
768 }
769 return new ListIteratorWrapper(iterator);
770 }
771
772 /**
773 * Gets an array based on an iterator.
774 * <p>
775 * As the wrapped Iterator is traversed, an ArrayList of its values is
776 * created. At the end, this is converted to an array.
777 *
778 * @param iterator the iterator to use, not null
779 * @return an array of the iterator contents
780 * @throws NullPointerException if iterator parameter is null
781 */
782 public static Object[] toArray(Iterator iterator) {
783 if (iterator == null) {
784 throw new NullPointerException("Iterator must not be null");
785 }
786 List list = toList(iterator, 100);
787 return list.toArray();
788 }
789
790 /**
791 * Gets an array based on an iterator.
792 * <p>
793 * As the wrapped Iterator is traversed, an ArrayList of its values is
794 * created. At the end, this is converted to an array.
795 *
796 * @param iterator the iterator to use, not null
797 * @param arrayClass the class of array to create
798 * @return an array of the iterator contents
799 * @throws NullPointerException if iterator parameter is null
800 * @throws NullPointerException if arrayClass is null
801 * @throws ClassCastException if the arrayClass is invalid
802 */
803 public static Object[] toArray(Iterator iterator, Class arrayClass) {
804 if (iterator == null) {
805 throw new NullPointerException("Iterator must not be null");
806 }
807 if (arrayClass == null) {
808 throw new NullPointerException("Array class must not be null");
809 }
810 List list = toList(iterator, 100);
811 return list.toArray((Object[]) Array.newInstance(arrayClass, list.size()));
812 }
813
814 /**
815 * Gets a list based on an iterator.
816 * <p>
817 * As the wrapped Iterator is traversed, an ArrayList of its values is
818 * created. At the end, the list is returned.
819 *
820 * @param iterator the iterator to use, not null
821 * @return a list of the iterator contents
822 * @throws NullPointerException if iterator parameter is null
823 */
824 public static List toList(Iterator iterator) {
825 return toList(iterator, 10);
826 }
827
828 /**
829 * Gets a list based on an iterator.
830 * <p>
831 * As the wrapped Iterator is traversed, an ArrayList of its values is
832 * created. At the end, the list is returned.
833 *
834 * @param iterator the iterator to use, not null
835 * @param estimatedSize the initial size of the ArrayList
836 * @return a list of the iterator contents
837 * @throws NullPointerException if iterator parameter is null
838 * @throws IllegalArgumentException if the size is less than 1
839 */
840 public static List toList(Iterator iterator, int estimatedSize) {
841 if (iterator == null) {
842 throw new NullPointerException("Iterator must not be null");
843 }
844 if (estimatedSize < 1) {
845 throw new IllegalArgumentException("Estimated size must be greater than 0");
846 }
847 List list = new ArrayList(estimatedSize);
848 while (iterator.hasNext()) {
849 list.add(iterator.next());
850 }
851 return list;
852 }
853
854 /**
855 * Gets a suitable Iterator for the given object.
856 * <p>
857 * This method can handles objects as follows
858 * <ul>
859 * <li>null - empty iterator
860 * <li>Iterator - returned directly
861 * <li>Enumeration - wrapped
862 * <li>Collection - iterator from collection returned
863 * <li>Map - values iterator returned
864 * <li>Dictionary - values (elements) enumeration returned as iterator
865 * <li>array - iterator over array returned
866 * <li>object with iterator() public method accessed by reflection
867 * <li>object - singleton iterator
868 * </ul>
869 *
870 * @param obj the object to convert to an iterator
871 * @return a suitable iterator, never null
872 */
873 public static Iterator getIterator(Object obj) {
874 if (obj == null) {
875 return emptyIterator();
876
877 } else if (obj instanceof Iterator) {
878 return (Iterator) obj;
879
880 } else if (obj instanceof Collection) {
881 return ((Collection) obj).iterator();
882
883 } else if (obj instanceof Object[]) {
884 return new ObjectArrayIterator((Object[]) obj);
885
886 } else if (obj instanceof Enumeration) {
887 return new EnumerationIterator((Enumeration) obj);
888
889 } else if (obj instanceof Map) {
890 return ((Map) obj).values().iterator();
891
892 } else if (obj instanceof Dictionary) {
893 return new EnumerationIterator(((Dictionary) obj).elements());
894
895 } else if (obj != null && obj.getClass().isArray()) {
896 return new ArrayIterator(obj);
897
898 } else {
899 try {
900 Method method = obj.getClass().getMethod("iterator", (Class[]) null);
901 if (Iterator.class.isAssignableFrom(method.getReturnType())) {
902 Iterator it = (Iterator) method.invoke(obj, (Object[]) null);
903 if (it != null) {
904 return it;
905 }
906 }
907 } catch (Exception ex) {
908 // ignore
909 }
910 return singletonIterator(obj);
911 }
912 }
913
914 }