View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections.iterators;
18  
19  import java.lang.reflect.Array;
20  import java.util.NoSuchElementException;
21  
22  import org.apache.commons.collections.ResettableIterator;
23  
24  /** 
25   * Implements an {@link java.util.Iterator Iterator} over any array.
26   * <p>
27   * The array can be either an array of object or of primitives. If you know 
28   * that you have an object array, the 
29   * {@link org.apache.commons.collections.iterators.ObjectArrayIterator ObjectArrayIterator}
30   * class is a better choice, as it will perform better.
31   * <p>
32   * The iterator implements a {@link #reset} method, allowing the reset of 
33   * the iterator back to the start if required.
34   *
35   * @since 1.0
36   * @version $Id: ArrayIterator.java 1429897 2013-01-07 17:04:52Z ggregory $
37   */
38  public class ArrayIterator<E> implements ResettableIterator<E> {
39  
40      /** The array to iterate over */    
41      protected Object array;
42      /** The start index to loop from */
43      protected int startIndex = 0;
44      /** The end index to loop to */
45      protected int endIndex = 0;
46      /** The current iterator index */
47      protected int index = 0;
48      
49      // Constructors
50      // ----------------------------------------------------------------------
51      /**
52       * Constructor for use with <code>setArray</code>.
53       * <p>
54       * Using this constructor, the iterator is equivalent to an empty iterator
55       * until {@link #setArray(Object)} is  called to establish the array to iterate over.
56       */
57      public ArrayIterator() {
58          super();
59      }
60     
61      /**
62       * Constructs an ArrayIterator that will iterate over the values in the
63       * specified array.
64       *
65       * @param array the array to iterate over.
66       * @throws IllegalArgumentException if <code>array</code> is not an array.
67       * @throws NullPointerException if <code>array</code> is <code>null</code>
68       */
69      public ArrayIterator(final Object array) {
70          super();
71          setArray(array);
72      }
73  
74      /**
75       * Constructs an ArrayIterator that will iterate over the values in the
76       * specified array from a specific start index.
77       *
78       * @param array  the array to iterate over.
79       * @param startIndex  the index to start iterating at.
80       * @throws IllegalArgumentException if <code>array</code> is not an array.
81       * @throws NullPointerException if <code>array</code> is <code>null</code>
82       * @throws IndexOutOfBoundsException if the index is invalid
83       */
84      public ArrayIterator(final Object array, final int startIndex) {
85          super();
86          setArray(array);
87          checkBound(startIndex, "start");
88          this.startIndex = startIndex;
89          this.index = startIndex;
90      }
91  
92      /**
93       * Construct an ArrayIterator that will iterate over a range of values 
94       * in the specified array.
95       *
96       * @param array  the array to iterate over.
97       * @param startIndex  the index to start iterating at.
98       * @param endIndex  the index to finish iterating at.
99       * @throws IllegalArgumentException if <code>array</code> is not an array.
100      * @throws NullPointerException if <code>array</code> is <code>null</code>
101      * @throws IndexOutOfBoundsException if either index is invalid
102      */
103     public ArrayIterator(final Object array, final int startIndex, final int endIndex) {
104         super();
105         setArray(array);
106         checkBound(startIndex, "start");
107         checkBound(endIndex, "end");
108         if (endIndex < startIndex) {
109             throw new IllegalArgumentException("End index must not be less than start index.");
110         }
111         this.startIndex = startIndex;
112         this.endIndex = endIndex;
113         this.index = startIndex;
114     }
115 
116     /**
117      * Checks whether the index is valid or not.
118      * 
119      * @param bound  the index to check
120      * @param type  the index type (for error messages)
121      * @throws IndexOutOfBoundsException if the index is invalid
122      */
123     protected void checkBound(final int bound, final String type ) {
124         if (bound > this.endIndex) {
125             throw new ArrayIndexOutOfBoundsException(
126               "Attempt to make an ArrayIterator that " + type +
127               "s beyond the end of the array. "
128             );
129         }
130         if (bound < 0) {
131             throw new ArrayIndexOutOfBoundsException(
132               "Attempt to make an ArrayIterator that " + type +
133               "s before the start of the array. "
134             );
135         }
136     }
137 
138     // Iterator interface
139     //-----------------------------------------------------------------------
140     /**
141      * Returns true if there are more elements to return from the array.
142      *
143      * @return true if there is a next element to return
144      */
145     public boolean hasNext() {
146         return index < endIndex;
147     }
148 
149     /**
150      * Returns the next element in the array.
151      *
152      * @return the next element in the array
153      * @throws NoSuchElementException if all the elements in the array
154      *  have already been returned
155      */
156     @SuppressWarnings("unchecked")
157     public E next() {
158         if (hasNext() == false) {
159             throw new NoSuchElementException();
160         }
161         return (E) Array.get(array, index++);
162     }
163 
164     /**
165      * Throws {@link UnsupportedOperationException}.
166      *
167      * @throws UnsupportedOperationException always
168      */
169     public void remove() {
170         throw new UnsupportedOperationException("remove() method is not supported");
171     }
172 
173     // Properties
174     //-----------------------------------------------------------------------
175     /**
176      * Gets the array that this iterator is iterating over. 
177      *
178      * @return the array this iterator iterates over, or <code>null</code> if
179      *  the no-arg constructor was used and {@link #setArray(Object)} has never
180      *  been called with a valid array.
181      */
182     public Object getArray() {
183         return array;
184     }
185     
186     /**
187      * Sets the array that the ArrayIterator should iterate over.
188      * <p>
189      * If an array has previously been set (using the single-arg constructor
190      * or this method) then that array is discarded in favour of this one.
191      * Iteration is restarted at the start of the new array.
192      * Although this can be used to reset iteration, the {@link #reset()} method
193      * is a more effective choice.
194      *
195      * @param array the array that the iterator should iterate over.
196      * @throws IllegalArgumentException if <code>array</code> is not an array.
197      * @throws NullPointerException if <code>array</code> is <code>null</code>
198      */
199     public void setArray(final Object array) {
200         // Array.getLength throws IllegalArgumentException if the object is not
201         // an array or NullPointerException if the object is null.  This call
202         // is made before saving the array and resetting the index so that the
203         // array iterator remains in a consistent state if the argument is not
204         // an array or is null.
205         this.endIndex = Array.getLength(array);
206         this.startIndex = 0;
207         this.array = array;
208         this.index = 0;
209     }
210     
211     /**
212      * Resets the iterator back to the start index.
213      */
214     public void reset() {
215         this.index = this.startIndex;
216     }
217 
218 }