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 }