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 }