001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.collections.iterators;
018
019 import java.lang.reflect.Array;
020 import java.util.NoSuchElementException;
021
022 import org.apache.commons.collections.ResettableIterator;
023
024 /**
025 * Implements an {@link java.util.Iterator Iterator} over any array.
026 * <p>
027 * The array can be either an array of object or of primitives. If you know
028 * that you have an object array, the
029 * {@link org.apache.commons.collections.iterators.ObjectArrayIterator ObjectArrayIterator}
030 * class is a better choice, as it will perform better.
031 * <p>
032 * The iterator implements a {@link #reset} method, allowing the reset of
033 * the iterator back to the start if required.
034 *
035 * @since Commons Collections 1.0
036 * @version $Revision: 647116 $ $Date: 2008-04-11 12:23:08 +0100 (Fri, 11 Apr 2008) $
037 *
038 * @author James Strachan
039 * @author Mauricio S. Moura
040 * @author Michael A. Smith
041 * @author Neil O'Toole
042 * @author Stephen Colebourne
043 */
044 public class ArrayIterator implements ResettableIterator {
045
046 /** The array to iterate over */
047 protected Object array;
048 /** The start index to loop from */
049 protected int startIndex = 0;
050 /** The end index to loop to */
051 protected int endIndex = 0;
052 /** The current iterator index */
053 protected int index = 0;
054
055 // Constructors
056 // ----------------------------------------------------------------------
057 /**
058 * Constructor for use with <code>setArray</code>.
059 * <p>
060 * Using this constructor, the iterator is equivalent to an empty iterator
061 * until {@link #setArray(Object)} is called to establish the array to iterate over.
062 */
063 public ArrayIterator() {
064 super();
065 }
066
067 /**
068 * Constructs an ArrayIterator that will iterate over the values in the
069 * specified array.
070 *
071 * @param array the array to iterate over.
072 * @throws IllegalArgumentException if <code>array</code> is not an array.
073 * @throws NullPointerException if <code>array</code> is <code>null</code>
074 */
075 public ArrayIterator(final Object array) {
076 super();
077 setArray(array);
078 }
079
080 /**
081 * Constructs an ArrayIterator that will iterate over the values in the
082 * specified array from a specific start index.
083 *
084 * @param array the array to iterate over.
085 * @param startIndex the index to start iterating at.
086 * @throws IllegalArgumentException if <code>array</code> is not an array.
087 * @throws NullPointerException if <code>array</code> is <code>null</code>
088 * @throws IndexOutOfBoundsException if the index is invalid
089 */
090 public ArrayIterator(final Object array, final int startIndex) {
091 super();
092 setArray(array);
093 checkBound(startIndex, "start");
094 this.startIndex = startIndex;
095 this.index = startIndex;
096 }
097
098 /**
099 * Construct an ArrayIterator that will iterate over a range of values
100 * in the specified array.
101 *
102 * @param array the array to iterate over.
103 * @param startIndex the index to start iterating at.
104 * @param endIndex the index to finish iterating at.
105 * @throws IllegalArgumentException if <code>array</code> is not an array.
106 * @throws NullPointerException if <code>array</code> is <code>null</code>
107 * @throws IndexOutOfBoundsException if either index is invalid
108 */
109 public ArrayIterator(final Object array, final int startIndex, final int endIndex) {
110 super();
111 setArray(array);
112 checkBound(startIndex, "start");
113 checkBound(endIndex, "end");
114 if (endIndex < startIndex) {
115 throw new IllegalArgumentException("End index must not be less than start index.");
116 }
117 this.startIndex = startIndex;
118 this.endIndex = endIndex;
119 this.index = startIndex;
120 }
121
122 /**
123 * Checks whether the index is valid or not.
124 *
125 * @param bound the index to check
126 * @param type the index type (for error messages)
127 * @throws IndexOutOfBoundsException if the index is invalid
128 */
129 protected void checkBound(final int bound, final String type ) {
130 if (bound > this.endIndex) {
131 throw new ArrayIndexOutOfBoundsException(
132 "Attempt to make an ArrayIterator that " + type +
133 "s beyond the end of the array. "
134 );
135 }
136 if (bound < 0) {
137 throw new ArrayIndexOutOfBoundsException(
138 "Attempt to make an ArrayIterator that " + type +
139 "s before the start of the array. "
140 );
141 }
142 }
143
144 // Iterator interface
145 //-----------------------------------------------------------------------
146 /**
147 * Returns true if there are more elements to return from the array.
148 *
149 * @return true if there is a next element to return
150 */
151 public boolean hasNext() {
152 return (index < endIndex);
153 }
154
155 /**
156 * Returns the next element in the array.
157 *
158 * @return the next element in the array
159 * @throws NoSuchElementException if all the elements in the array
160 * have already been returned
161 */
162 public Object next() {
163 if (hasNext() == false) {
164 throw new NoSuchElementException();
165 }
166 return Array.get(array, index++);
167 }
168
169 /**
170 * Throws {@link UnsupportedOperationException}.
171 *
172 * @throws UnsupportedOperationException always
173 */
174 public void remove() {
175 throw new UnsupportedOperationException("remove() method is not supported");
176 }
177
178 // Properties
179 //-----------------------------------------------------------------------
180 /**
181 * Gets the array that this iterator is iterating over.
182 *
183 * @return the array this iterator iterates over, or <code>null</code> if
184 * the no-arg constructor was used and {@link #setArray(Object)} has never
185 * been called with a valid array.
186 */
187 public Object getArray() {
188 return array;
189 }
190
191 /**
192 * Sets the array that the ArrayIterator should iterate over.
193 * <p>
194 * If an array has previously been set (using the single-arg constructor
195 * or this method) then that array is discarded in favour of this one.
196 * Iteration is restarted at the start of the new array.
197 * Although this can be used to reset iteration, the {@link #reset()} method
198 * is a more effective choice.
199 *
200 * @param array the array that the iterator should iterate over.
201 * @throws IllegalArgumentException if <code>array</code> is not an array.
202 * @throws NullPointerException if <code>array</code> is <code>null</code>
203 */
204 public void setArray(final Object array) {
205 // Array.getLength throws IllegalArgumentException if the object is not
206 // an array or NullPointerException if the object is null. This call
207 // is made before saving the array and resetting the index so that the
208 // array iterator remains in a consistent state if the argument is not
209 // an array or is null.
210 this.endIndex = Array.getLength(array);
211 this.startIndex = 0;
212 this.array = array;
213 this.index = 0;
214 }
215
216 /**
217 * Resets the iterator back to the start index.
218 */
219 public void reset() {
220 this.index = this.startIndex;
221 }
222
223 }