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