1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.collections;
  17. import java.lang.reflect.Array;
  18. import java.lang.reflect.Method;
  19. import java.util.ArrayList;
  20. import java.util.Collection;
  21. import java.util.Comparator;
  22. import java.util.Dictionary;
  23. import java.util.Enumeration;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.ListIterator;
  27. import java.util.Map;
  28. import org.apache.commons.collections.iterators.ArrayIterator;
  29. import org.apache.commons.collections.iterators.ArrayListIterator;
  30. import org.apache.commons.collections.iterators.CollatingIterator;
  31. import org.apache.commons.collections.iterators.EmptyIterator;
  32. import org.apache.commons.collections.iterators.EmptyListIterator;
  33. import org.apache.commons.collections.iterators.EmptyMapIterator;
  34. import org.apache.commons.collections.iterators.EmptyOrderedIterator;
  35. import org.apache.commons.collections.iterators.EmptyOrderedMapIterator;
  36. import org.apache.commons.collections.iterators.EnumerationIterator;
  37. import org.apache.commons.collections.iterators.FilterIterator;
  38. import org.apache.commons.collections.iterators.FilterListIterator;
  39. import org.apache.commons.collections.iterators.IteratorChain;
  40. import org.apache.commons.collections.iterators.IteratorEnumeration;
  41. import org.apache.commons.collections.iterators.ListIteratorWrapper;
  42. import org.apache.commons.collections.iterators.LoopingIterator;
  43. import org.apache.commons.collections.iterators.ObjectArrayIterator;
  44. import org.apache.commons.collections.iterators.ObjectArrayListIterator;
  45. import org.apache.commons.collections.iterators.ObjectGraphIterator;
  46. import org.apache.commons.collections.iterators.SingletonIterator;
  47. import org.apache.commons.collections.iterators.SingletonListIterator;
  48. import org.apache.commons.collections.iterators.TransformIterator;
  49. import org.apache.commons.collections.iterators.UnmodifiableIterator;
  50. import org.apache.commons.collections.iterators.UnmodifiableListIterator;
  51. import org.apache.commons.collections.iterators.UnmodifiableMapIterator;
  52. /**
  53. * Provides static utility methods and decorators for {@link Iterator}
  54. * instances. The implementations are provided in the iterators subpackage.
  55. * <p>
  56. * WARNING: Due to human error certain binary incompatabilities were introduced
  57. * between Commons Collections 2.1 and 3.0. The class remained source and test
  58. * compatible, so if you can recompile all your classes and dependencies
  59. * everything is OK. Those methods which are binary incompatible are marked as
  60. * such, together with alternate solutions that are binary compatible
  61. * against versions 2.1.1 and 3.1.
  62. *
  63. * @since Commons Collections 2.1
  64. * @version $Revision: 1.27 $ $Date: 2004/05/26 21:53:46 $
  65. *
  66. * @author Stephen Colebourne
  67. * @author Phil Steitz
  68. */
  69. public class IteratorUtils {
  70. // validation is done in this class in certain cases because the
  71. // public classes allow invalid states
  72. /**
  73. * An iterator over no elements.
  74. * <p>
  75. * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
  76. * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
  77. */
  78. public static final ResettableIterator EMPTY_ITERATOR = EmptyIterator.RESETTABLE_INSTANCE;
  79. /**
  80. * A list iterator over no elements.
  81. * <p>
  82. * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
  83. * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
  84. */
  85. public static final ResettableListIterator EMPTY_LIST_ITERATOR = EmptyListIterator.RESETTABLE_INSTANCE;
  86. /**
  87. * An ordered iterator over no elements.
  88. */
  89. public static final OrderedIterator EMPTY_ORDERED_ITERATOR = EmptyOrderedIterator.INSTANCE;
  90. /**
  91. * A map iterator over no elements.
  92. */
  93. public static final MapIterator EMPTY_MAP_ITERATOR = EmptyMapIterator.INSTANCE;
  94. /**
  95. * An ordered map iterator over no elements.
  96. */
  97. public static final OrderedMapIterator EMPTY_ORDERED_MAP_ITERATOR = EmptyOrderedMapIterator.INSTANCE;
  98. /**
  99. * IteratorUtils is not normally instantiated.
  100. */
  101. public IteratorUtils() {
  102. }
  103. // Empty
  104. //-----------------------------------------------------------------------
  105. /**
  106. * Gets an empty iterator.
  107. * <p>
  108. * This iterator is a valid iterator object that will iterate over
  109. * nothing.
  110. * <p>
  111. * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
  112. * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
  113. *
  114. * @return an iterator over nothing
  115. */
  116. public static ResettableIterator emptyIterator() {
  117. return EMPTY_ITERATOR;
  118. }
  119. /**
  120. * Gets an empty list iterator.
  121. * <p>
  122. * This iterator is a valid list iterator object that will iterate
  123. * over nothing.
  124. * <p>
  125. * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
  126. * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
  127. *
  128. * @return a list iterator over nothing
  129. */
  130. public static ResettableListIterator emptyListIterator() {
  131. return EMPTY_LIST_ITERATOR;
  132. }
  133. /**
  134. * Gets an empty ordered iterator.
  135. * <p>
  136. * This iterator is a valid iterator object that will iterate
  137. * over nothing.
  138. *
  139. * @return an ordered iterator over nothing
  140. */
  141. public static OrderedIterator emptyOrderedIterator() {
  142. return EMPTY_ORDERED_ITERATOR;
  143. }
  144. /**
  145. * Gets an empty map iterator.
  146. * <p>
  147. * This iterator is a valid map iterator object that will iterate
  148. * over nothing.
  149. *
  150. * @return a map iterator over nothing
  151. */
  152. public static MapIterator emptyMapIterator() {
  153. return EMPTY_MAP_ITERATOR;
  154. }
  155. /**
  156. * Gets an empty ordered 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 OrderedMapIterator emptyOrderedMapIterator() {
  164. return EMPTY_ORDERED_MAP_ITERATOR;
  165. }
  166. // Singleton
  167. //-----------------------------------------------------------------------
  168. /**
  169. * Gets a singleton iterator.
  170. * <p>
  171. * This iterator is a valid iterator object that will iterate over
  172. * the specified object.
  173. * <p>
  174. * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
  175. * Use <code>new SingletonIterator(object)</code> for compatability.
  176. *
  177. * @param object the single object over which to iterate
  178. * @return a singleton iterator over the object
  179. */
  180. public static ResettableIterator singletonIterator(Object object) {
  181. return new SingletonIterator(object);
  182. }
  183. /**
  184. * Gets a singleton list iterator.
  185. * <p>
  186. * This iterator is a valid list iterator object that will iterate over
  187. * the specified object.
  188. *
  189. * @param object the single object over which to iterate
  190. * @return a singleton list iterator over the object
  191. */
  192. public static ListIterator singletonListIterator(Object object) {
  193. return new SingletonListIterator(object);
  194. }
  195. // Arrays
  196. //-----------------------------------------------------------------------
  197. /**
  198. * Gets an iterator over an object array.
  199. * <p>
  200. * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
  201. * Use <code>new ArrayIterator(array)</code> for compatability.
  202. *
  203. * @param array the array over which to iterate
  204. * @return an iterator over the array
  205. * @throws NullPointerException if array is null
  206. */
  207. public static ResettableIterator arrayIterator(Object[] array) {
  208. return new ObjectArrayIterator(array);
  209. }
  210. /**
  211. * Gets an iterator over an object or primitive array.
  212. * <p>
  213. * This method will handle primitive arrays as well as object arrays.
  214. * The primitives will be wrapped in the appropriate wrapper class.
  215. *
  216. * @param array the array over which to iterate
  217. * @return an iterator over the array
  218. * @throws IllegalArgumentException if the array is not an array
  219. * @throws NullPointerException if array is null
  220. */
  221. public static ResettableIterator arrayIterator(Object array) {
  222. return new ArrayIterator(array);
  223. }
  224. /**
  225. * Gets an iterator over the end part of an object array.
  226. * <p>
  227. * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
  228. * Use <code>new ArrayIterator(array,start)</code> for compatability.
  229. *
  230. * @param array the array over which to iterate
  231. * @param start the index to start iterating at
  232. * @return an iterator over part of the array
  233. * @throws IndexOutOfBoundsException if start is less than zero or greater
  234. * than the length of the array
  235. * @throws NullPointerException if array is null
  236. */
  237. public static ResettableIterator arrayIterator(Object[] array, int start) {
  238. return new ObjectArrayIterator(array, start);
  239. }
  240. /**
  241. * Gets an iterator over the end part of an object or primitive array.
  242. * <p>
  243. * This method will handle primitive arrays as well as object arrays.
  244. * The primitives will be wrapped in the appropriate wrapper class.
  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 IllegalArgumentException if the array is not an 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 ArrayIterator(array, start);
  256. }
  257. /**
  258. * Gets an iterator over part of an object array.
  259. * <p>
  260. * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
  261. * Use <code>new ArrayIterator(array,start,end)</code> for compatability.
  262. *
  263. * @param array the array over which to iterate
  264. * @param start the index to start iterating at
  265. * @param end the index to finish iterating at
  266. * @return an iterator over part of the array
  267. * @throws IndexOutOfBoundsException if array bounds are invalid
  268. * @throws IllegalArgumentException if end is before start
  269. * @throws NullPointerException if array is null
  270. */
  271. public static ResettableIterator arrayIterator(Object[] array, int start, int end) {
  272. return new ObjectArrayIterator(array, start, end);
  273. }
  274. /**
  275. * Gets an iterator over part of an object or primitive array.
  276. * <p>
  277. * This method will handle primitive arrays as well as object arrays.
  278. * The primitives will be wrapped in the appropriate wrapper class.
  279. *
  280. * @param array the array over which to iterate
  281. * @param start the index to start iterating at
  282. * @param end the index to finish iterating at
  283. * @return an iterator over part of the array
  284. * @throws IllegalArgumentException if the array is not an array
  285. * @throws IndexOutOfBoundsException if array bounds are invalid
  286. * @throws IllegalArgumentException if end is before start
  287. * @throws NullPointerException if array is null
  288. */
  289. public static ResettableIterator arrayIterator(Object array, int start, int end) {
  290. return new ArrayIterator(array, start, end);
  291. }
  292. //-----------------------------------------------------------------------
  293. /**
  294. * Gets a list iterator over an object array.
  295. *
  296. * @param array the array over which to iterate
  297. * @return a list iterator over the array
  298. * @throws NullPointerException if array is null
  299. */
  300. public static ResettableListIterator arrayListIterator(Object[] array) {
  301. return new ObjectArrayListIterator(array);
  302. }
  303. /**
  304. * Gets a list iterator over an object or primitive array.
  305. * <p>
  306. * This method will handle primitive arrays as well as object arrays.
  307. * The primitives will be wrapped in the appropriate wrapper class.
  308. *
  309. * @param array the array over which to iterate
  310. * @return a list iterator over the array
  311. * @throws IllegalArgumentException if the array is not an array
  312. * @throws NullPointerException if array is null
  313. */
  314. public static ResettableListIterator arrayListIterator(Object array) {
  315. return new ArrayListIterator(array);
  316. }
  317. /**
  318. * Gets a list iterator over the end part of an object array.
  319. *
  320. * @param array the array over which to iterate
  321. * @param start the index to start iterating at
  322. * @return a list iterator over part of the array
  323. * @throws IndexOutOfBoundsException if start is less than zero
  324. * @throws NullPointerException if array is null
  325. */
  326. public static ResettableListIterator arrayListIterator(Object[] array, int start) {
  327. return new ObjectArrayListIterator(array, start);
  328. }
  329. /**
  330. * Gets a list iterator over the end part of 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. * @param start the index to start iterating at
  337. * @return a list iterator over part of the array
  338. * @throws IllegalArgumentException if the array is not an array
  339. * @throws IndexOutOfBoundsException if start is less than zero
  340. * @throws NullPointerException if array is null
  341. */
  342. public static ResettableListIterator arrayListIterator(Object array, int start) {
  343. return new ArrayListIterator(array, start);
  344. }
  345. /**
  346. * Gets a list iterator over part of an object array.
  347. *
  348. * @param array the array over which to iterate
  349. * @param start the index to start iterating at
  350. * @param end the index to finish iterating at
  351. * @return a list iterator over part of the array
  352. * @throws IndexOutOfBoundsException if array bounds are invalid
  353. * @throws IllegalArgumentException if end is before start
  354. * @throws NullPointerException if array is null
  355. */
  356. public static ResettableListIterator arrayListIterator(Object[] array, int start, int end) {
  357. return new ObjectArrayListIterator(array, start, end);
  358. }
  359. /**
  360. * Gets a list iterator over part of an object or primitive array.
  361. * <p>
  362. * This method will handle primitive arrays as well as object arrays.
  363. * The primitives will be wrapped in the appropriate wrapper class.
  364. *
  365. * @param array the array over which to iterate
  366. * @param start the index to start iterating at
  367. * @param end the index to finish iterating at
  368. * @return a list iterator over part of the array
  369. * @throws IllegalArgumentException if the array is not an array
  370. * @throws IndexOutOfBoundsException if array bounds are invalid
  371. * @throws IllegalArgumentException if end is before start
  372. * @throws NullPointerException if array is null
  373. */
  374. public static ResettableListIterator arrayListIterator(Object array, int start, int end) {
  375. return new ArrayListIterator(array, start, end);
  376. }
  377. // Unmodifiable
  378. //-----------------------------------------------------------------------
  379. /**
  380. * Gets an immutable version of an {@link Iterator}. The returned object
  381. * will always throw an {@link UnsupportedOperationException} for
  382. * the {@link Iterator#remove} method.
  383. *
  384. * @param iterator the iterator to make immutable
  385. * @return an immutable version of the iterator
  386. */
  387. public static Iterator unmodifiableIterator(Iterator iterator) {
  388. return UnmodifiableIterator.decorate(iterator);
  389. }
  390. /**
  391. * Gets an immutable version of a {@link ListIterator}. The returned object
  392. * will always throw an {@link UnsupportedOperationException} for
  393. * the {@link Iterator#remove}, {@link ListIterator#add} and
  394. * {@link ListIterator#set} methods.
  395. *
  396. * @param listIterator the iterator to make immutable
  397. * @return an immutable version of the iterator
  398. */
  399. public static ListIterator unmodifiableListIterator(ListIterator listIterator) {
  400. return UnmodifiableListIterator.decorate(listIterator);
  401. }
  402. /**
  403. * Gets an immutable version of a {@link MapIterator}. The returned object
  404. * will always throw an {@link UnsupportedOperationException} for
  405. * the {@link Iterator#remove}, {@link MapIterator#setValue(Object)} methods.
  406. *
  407. * @param mapIterator the iterator to make immutable
  408. * @return an immutable version of the iterator
  409. */
  410. public static MapIterator unmodifiableMapIterator(MapIterator mapIterator) {
  411. return UnmodifiableMapIterator.decorate(mapIterator);
  412. }
  413. // Chained
  414. //-----------------------------------------------------------------------
  415. /**
  416. * Gets an iterator that iterates through two {@link Iterator}s
  417. * one after another.
  418. *
  419. * @param iterator1 the first iterators to use, not null
  420. * @param iterator2 the first iterators to use, not null
  421. * @return a combination iterator over the iterators
  422. * @throws NullPointerException if either iterator is null
  423. */
  424. public static Iterator chainedIterator(Iterator iterator1, Iterator iterator2) {
  425. return new IteratorChain(iterator1, iterator2);
  426. }
  427. /**
  428. * Gets an iterator that iterates through an array of {@link Iterator}s
  429. * one after another.
  430. *
  431. * @param iterators the iterators to use, not null or empty or contain nulls
  432. * @return a combination iterator over the iterators
  433. * @throws NullPointerException if iterators array is null or contains a null
  434. */
  435. public static Iterator chainedIterator(Iterator[] iterators) {
  436. return new IteratorChain(iterators);
  437. }
  438. /**
  439. * Gets an iterator that iterates through a collections of {@link Iterator}s
  440. * one after another.
  441. *
  442. * @param iterators the iterators to use, not null or empty or contain nulls
  443. * @return a combination iterator over the iterators
  444. * @throws NullPointerException if iterators collection is null or contains a null
  445. * @throws ClassCastException if the iterators collection contains the wrong object type
  446. */
  447. public static Iterator chainedIterator(Collection iterators) {
  448. return new IteratorChain(iterators);
  449. }
  450. // Collated
  451. //-----------------------------------------------------------------------
  452. /**
  453. * Gets an iterator that provides an ordered iteration over the elements
  454. * contained in a collection of ordered {@link Iterator}s.
  455. * <p>
  456. * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
  457. * the {@link Iterator#next()} method will return the lesser of
  458. * <code>A.next()</code> and <code>B.next()</code>.
  459. * <p>
  460. * The comparator is optional. If null is specified then natural order is used.
  461. *
  462. * @param comparator the comparator to use, may be null for natural order
  463. * @param iterator1 the first iterators to use, not null
  464. * @param iterator2 the first iterators to use, not null
  465. * @return a combination iterator over the iterators
  466. * @throws NullPointerException if either iterator is null
  467. */
  468. public static Iterator collatedIterator(Comparator comparator, Iterator iterator1, Iterator iterator2) {
  469. return new CollatingIterator(comparator, iterator1, iterator2);
  470. }
  471. /**
  472. * Gets an iterator that provides an ordered iteration over the elements
  473. * contained in an array of {@link Iterator}s.
  474. * <p>
  475. * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
  476. * the {@link Iterator#next()} method will return the lesser of
  477. * <code>A.next()</code> and <code>B.next()</code> and so on.
  478. * <p>
  479. * The comparator is optional. If null is specified then natural order is used.
  480. *
  481. * @param comparator the comparator to use, may be null for natural order
  482. * @param iterators the iterators to use, not null or empty or contain nulls
  483. * @return a combination iterator over the iterators
  484. * @throws NullPointerException if iterators array is null or contains a null
  485. */
  486. public static Iterator collatedIterator(Comparator comparator, Iterator[] iterators) {
  487. return new CollatingIterator(comparator, iterators);
  488. }
  489. /**
  490. * Gets an iterator that provides an ordered iteration over the elements
  491. * contained in a collection of {@link Iterator}s.
  492. * <p>
  493. * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
  494. * the {@link Iterator#next()} method will return the lesser of
  495. * <code>A.next()</code> and <code>B.next()</code> and so on.
  496. * <p>
  497. * The comparator is optional. If null is specified then natural order is used.
  498. *
  499. * @param comparator the comparator to use, may be null for natural order
  500. * @param iterators the iterators to use, not null or empty or contain nulls
  501. * @return a combination iterator over the iterators
  502. * @throws NullPointerException if iterators collection is null or contains a null
  503. * @throws ClassCastException if the iterators collection contains the wrong object type
  504. */
  505. public static Iterator collatedIterator(Comparator comparator, Collection iterators) {
  506. return new CollatingIterator(comparator, iterators);
  507. }
  508. // Object Graph
  509. //-----------------------------------------------------------------------
  510. /**
  511. * Gets an iterator that operates over an object graph.
  512. * <p>
  513. * This iterator can extract multiple objects from a complex tree-like object graph.
  514. * The iteration starts from a single root object.
  515. * It uses a <code>Transformer</code> to extract the iterators and elements.
  516. * Its main benefit is that no intermediate <code>List</code> is created.
  517. * <p>
  518. * For example, consider an object graph:
  519. * <pre>
  520. * |- Branch -- Leaf
  521. * | \- Leaf
  522. * |- Tree | /- Leaf
  523. * | |- Branch -- Leaf
  524. * Forest | \- Leaf
  525. * | |- Branch -- Leaf
  526. * | | \- Leaf
  527. * |- Tree | /- Leaf
  528. * |- Branch -- Leaf
  529. * |- Branch -- Leaf</pre>
  530. * The following <code>Transformer</code>, used in this class, will extract all
  531. * the Leaf objects without creating a combined intermediate list:
  532. * <pre>
  533. * public Object transform(Object input) {
  534. * if (input instanceof Forest) {
  535. * return ((Forest) input).treeIterator();
  536. * }
  537. * if (input instanceof Tree) {
  538. * return ((Tree) input).branchIterator();
  539. * }
  540. * if (input instanceof Branch) {
  541. * return ((Branch) input).leafIterator();
  542. * }
  543. * if (input instanceof Leaf) {
  544. * return input;
  545. * }
  546. * throw new ClassCastException();
  547. * }</pre>
  548. * <p>
  549. * Internally, iteration starts from the root object. When next is called,
  550. * the transformer is called to examine the object. The transformer will return
  551. * either an iterator or an object. If the object is an Iterator, the next element
  552. * from that iterator is obtained and the process repeats. If the element is an object
  553. * it is returned.
  554. * <p>
  555. * Under many circumstances, linking Iterators together in this manner is
  556. * more efficient (and convenient) than using nested for loops to extract a list.
  557. *
  558. * @param root the root object to start iterating from, null results in an empty iterator
  559. * @param transformer the transformer to use, see above, null uses no effect transformer
  560. * @return a new object graph iterator
  561. * @since Commons Collections 3.1
  562. */
  563. public static Iterator objectGraphIterator(Object root, Transformer transformer) {
  564. return new ObjectGraphIterator(root, transformer);
  565. }
  566. // Transformed
  567. //-----------------------------------------------------------------------
  568. /**
  569. * Gets an iterator that transforms the elements of another iterator.
  570. * <p>
  571. * The transformation occurs during the next() method and the underlying
  572. * iterator is unaffected by the transformation.
  573. *
  574. * @param iterator the iterator to use, not null
  575. * @param transform the transform to use, not null
  576. * @return a new transforming iterator
  577. * @throws NullPointerException if either parameter is null
  578. */
  579. public static Iterator transformedIterator(Iterator iterator, Transformer transform) {
  580. if (iterator == null) {
  581. throw new NullPointerException("Iterator must not be null");
  582. }
  583. if (transform == null) {
  584. throw new NullPointerException("Transformer must not be null");
  585. }
  586. return new TransformIterator(iterator, transform);
  587. }
  588. // Filtered
  589. //-----------------------------------------------------------------------
  590. /**
  591. * Gets an iterator that filters another iterator.
  592. * <p>
  593. * The returned iterator will only return objects that match the specified
  594. * filtering predicate.
  595. *
  596. * @param iterator the iterator to use, not null
  597. * @param predicate the predicate to use as a filter, not null
  598. * @return a new filtered iterator
  599. * @throws NullPointerException if either parameter is null
  600. */
  601. public static Iterator filteredIterator(Iterator iterator, Predicate predicate) {
  602. if (iterator == null) {
  603. throw new NullPointerException("Iterator must not be null");
  604. }
  605. if (predicate == null) {
  606. throw new NullPointerException("Predicate must not be null");
  607. }
  608. return new FilterIterator(iterator, predicate);
  609. }
  610. /**
  611. * Gets a list iterator that filters another list iterator.
  612. * <p>
  613. * The returned iterator will only return objects that match the specified
  614. * filtering predicate.
  615. *
  616. * @param listIterator the list iterator to use, not null
  617. * @param predicate the predicate to use as a filter, not null
  618. * @return a new filtered iterator
  619. * @throws NullPointerException if either parameter is null
  620. */
  621. public static ListIterator filteredListIterator(ListIterator listIterator, Predicate predicate) {
  622. if (listIterator == null) {
  623. throw new NullPointerException("ListIterator must not be null");
  624. }
  625. if (predicate == null) {
  626. throw new NullPointerException("Predicate must not be null");
  627. }
  628. return new FilterListIterator(listIterator, predicate);
  629. }
  630. // Looping
  631. //-----------------------------------------------------------------------
  632. /**
  633. * Gets an iterator that loops continuously over the supplied collection.
  634. * <p>
  635. * The iterator will only stop looping if the remove method is called
  636. * enough times to empty the collection, or if the collection is empty
  637. * to start with.
  638. *
  639. * @param coll the collection to iterate over, not null
  640. * @return a new looping iterator
  641. * @throws NullPointerException if the collection is null
  642. */
  643. public static ResettableIterator loopingIterator(Collection coll) {
  644. if (coll == null) {
  645. throw new NullPointerException("Collection must not be null");
  646. }
  647. return new LoopingIterator(coll);
  648. }
  649. // Views
  650. //-----------------------------------------------------------------------
  651. /**
  652. * Gets an iterator that provides an iterator view of the given enumeration.
  653. *
  654. * @param enumeration the enumeration to use
  655. * @return a new iterator
  656. */
  657. public static Iterator asIterator(Enumeration enumeration) {
  658. if (enumeration == null) {
  659. throw new NullPointerException("Enumeration must not be null");
  660. }
  661. return new EnumerationIterator(enumeration);
  662. }
  663. /**
  664. * Gets an iterator that provides an iterator view of the given enumeration
  665. * that will remove elements from the specified collection.
  666. *
  667. * @param enumeration the enumeration to use
  668. * @param removeCollection the collection to remove elements from
  669. * @return a new iterator
  670. */
  671. public static Iterator asIterator(Enumeration enumeration, Collection removeCollection) {
  672. if (enumeration == null) {
  673. throw new NullPointerException("Enumeration must not be null");
  674. }
  675. if (removeCollection == null) {
  676. throw new NullPointerException("Collection must not be null");
  677. }
  678. return new EnumerationIterator(enumeration, removeCollection);
  679. }
  680. /**
  681. * Gets an enumeration that wraps an iterator.
  682. *
  683. * @param iterator the iterator to use, not null
  684. * @return a new enumeration
  685. * @throws NullPointerException if iterator is null
  686. */
  687. public static Enumeration asEnumeration(Iterator iterator) {
  688. if (iterator == null) {
  689. throw new NullPointerException("Iterator must not be null");
  690. }
  691. return new IteratorEnumeration(iterator);
  692. }
  693. /**
  694. * Gets a list iterator based on a simple iterator.
  695. * <p>
  696. * As the wrapped Iterator is traversed, a LinkedList of its values is
  697. * cached, permitting all required operations of ListIterator.
  698. *
  699. * @param iterator the iterator to use, not null
  700. * @return a new iterator
  701. * @throws NullPointerException if iterator parameter is null
  702. */
  703. public static ListIterator toListIterator(Iterator iterator) {
  704. if (iterator == null) {
  705. throw new NullPointerException("Iterator must not be null");
  706. }
  707. return new ListIteratorWrapper(iterator);
  708. }
  709. /**
  710. * Gets an array based on an iterator.
  711. * <p>
  712. * As the wrapped Iterator is traversed, an ArrayList of its values is
  713. * created. At the end, this is converted to an array.
  714. *
  715. * @param iterator the iterator to use, not null
  716. * @return an array of the iterator contents
  717. * @throws NullPointerException if iterator parameter is null
  718. */
  719. public static Object[] toArray(Iterator iterator) {
  720. if (iterator == null) {
  721. throw new NullPointerException("Iterator must not be null");
  722. }
  723. List list = toList(iterator, 100);
  724. return list.toArray();
  725. }
  726. /**
  727. * Gets an array based on an iterator.
  728. * <p>
  729. * As the wrapped Iterator is traversed, an ArrayList of its values is
  730. * created. At the end, this is converted to an array.
  731. *
  732. * @param iterator the iterator to use, not null
  733. * @param arrayClass the class of array to create
  734. * @return an array of the iterator contents
  735. * @throws NullPointerException if iterator parameter is null
  736. * @throws NullPointerException if arrayClass is null
  737. * @throws ClassCastException if the arrayClass is invalid
  738. */
  739. public static Object[] toArray(Iterator iterator, Class arrayClass) {
  740. if (iterator == null) {
  741. throw new NullPointerException("Iterator must not be null");
  742. }
  743. if (arrayClass == null) {
  744. throw new NullPointerException("Array class must not be null");
  745. }
  746. List list = toList(iterator, 100);
  747. return list.toArray((Object[]) Array.newInstance(arrayClass, list.size()));
  748. }
  749. /**
  750. * Gets a list based on an iterator.
  751. * <p>
  752. * As the wrapped Iterator is traversed, an ArrayList of its values is
  753. * created. At the end, the list is returned.
  754. *
  755. * @param iterator the iterator to use, not null
  756. * @return a list of the iterator contents
  757. * @throws NullPointerException if iterator parameter is null
  758. */
  759. public static List toList(Iterator iterator) {
  760. return toList(iterator, 10);
  761. }
  762. /**
  763. * Gets a list based on an iterator.
  764. * <p>
  765. * As the wrapped Iterator is traversed, an ArrayList of its values is
  766. * created. At the end, the list is returned.
  767. *
  768. * @param iterator the iterator to use, not null
  769. * @param estimatedSize the initial size of the ArrayList
  770. * @return a list of the iterator contents
  771. * @throws NullPointerException if iterator parameter is null
  772. * @throws IllegalArgumentException if the size is less than 1
  773. */
  774. public static List toList(Iterator iterator, int estimatedSize) {
  775. if (iterator == null) {
  776. throw new NullPointerException("Iterator must not be null");
  777. }
  778. if (estimatedSize < 1) {
  779. throw new IllegalArgumentException("Estimated size must be greater than 0");
  780. }
  781. List list = new ArrayList(estimatedSize);
  782. while (iterator.hasNext()) {
  783. list.add(iterator.next());
  784. }
  785. return list;
  786. }
  787. /**
  788. * Gets a suitable Iterator for the given object.
  789. * <p>
  790. * This method can handles objects as follows
  791. * <ul>
  792. * <li>null - empty iterator
  793. * <li>Iterator - returned directly
  794. * <li>Enumeration - wrapped
  795. * <li>Collection - iterator from collection returned
  796. * <li>Map - values iterator returned
  797. * <li>Dictionary - values (elements) enumeration returned as iterator
  798. * <li>array - iterator over array returned
  799. * <li>object with iterator() public method accessed by reflection
  800. * <li>object - singleton iterator
  801. * </ul>
  802. *
  803. * @param obj the object to convert to an iterator
  804. * @return a suitable iterator, never null
  805. */
  806. public static Iterator getIterator(Object obj) {
  807. if (obj == null) {
  808. return emptyIterator();
  809. } else if (obj instanceof Iterator) {
  810. return (Iterator) obj;
  811. } else if (obj instanceof Collection) {
  812. return ((Collection) obj).iterator();
  813. } else if (obj instanceof Object[]) {
  814. return new ObjectArrayIterator((Object[]) obj);
  815. } else if (obj instanceof Enumeration) {
  816. return new EnumerationIterator((Enumeration) obj);
  817. } else if (obj instanceof Map) {
  818. return ((Map) obj).values().iterator();
  819. } else if (obj instanceof Dictionary) {
  820. return new EnumerationIterator(((Dictionary) obj).elements());
  821. } else if (obj != null && obj.getClass().isArray()) {
  822. return new ArrayIterator(obj);
  823. } else {
  824. try {
  825. Method method = obj.getClass().getMethod("iterator", null);
  826. if (Iterator.class.isAssignableFrom(method.getReturnType())) {
  827. Iterator it = (Iterator) method.invoke(obj, null);
  828. if (it != null) {
  829. return it;
  830. }
  831. }
  832. } catch (Exception ex) {
  833. // ignore
  834. }
  835. return singletonIterator(obj);
  836. }
  837. }
  838. }