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 }