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