    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 *      https://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 */
    017package org.apache.commons.collections4.iterators;
    018
    019import java.lang.reflect.Array;
    020import java.util.Iterator;
    021import java.util.NoSuchElementException;
    022
    023import org.apache.commons.collections4.ResettableIterator;
    024
    025/**
    026 * Implements an {@link Iterator Iterator} over any array.
    027 * <p>
    028 * The array can be either an array of object or of primitives. If you know
    029 * that you have an object array, the
    030 * {@link ObjectArrayIterator ObjectArrayIterator}
    031 * class is a better choice, as it will perform better.
    032 * </p>
    033 * <p>
    034 * The iterator implements a {@link #reset} method, allowing the reset of
    035 * the iterator back to the start if required.
    036 * </p>
    037 *
    038 * @param <E> The type of elements returned by this iterator.
    039 * @since 1.0
    040 */
    041public class ArrayIterator<E> implements ResettableIterator<E> {
    042
    043    /** The array to iterate over */
    044    final Object array;
    045
    046    /** The start index to loop from */
    047    final int startIndex;
    048
    049    /** The end index to loop to */
    050    final int endIndex;
    051
    052    /** The current iterator index */
    053    int index;
    054
    055    /**
    056     * Constructs an ArrayIterator that will iterate over the values in the
    057     * specified array.
    058     *
    059     * @param array The array to iterate over.
    060     * @throws IllegalArgumentException if {@code array} is not an array.
    061     * @throws NullPointerException if {@code array} is {@code null}
    062     */
    063    public ArrayIterator(final Object array) {
    064        this(array, 0);
    065    }
    066
    067    /**
    068     * Constructs an ArrayIterator that will iterate over the values in the
    069     * specified array from a specific start index.
    070     *
    071     * @param array  The array to iterate over.
    072     * @param startIndex  The index to start iterating at.
    073     * @throws IllegalArgumentException if {@code array} is not an array.
    074     * @throws NullPointerException if {@code array} is {@code null}
    075     * @throws IndexOutOfBoundsException if the index is invalid
    076     */
    077    public ArrayIterator(final Object array, final int startIndex) {
    078        this(array, startIndex, Array.getLength(array));
    079    }
    080
    081    /**
    082     * Constructs an ArrayIterator that will iterate over a range of values
    083     * in the specified array.
    084     *
    085     * @param array  The array to iterate over.
    086     * @param startIndex  The index to start iterating at.
    087     * @param endIndex  The index to finish iterating at.
    088     * @throws IllegalArgumentException if {@code array} is not an array.
    089     * @throws NullPointerException if {@code array} is {@code null}
    090     * @throws IndexOutOfBoundsException if either index is invalid
    091     */
    092    public ArrayIterator(final Object array, final int startIndex, final int endIndex) {
    093        this.array = array;
    094        this.startIndex = startIndex;
    095        this.endIndex = endIndex;
    096        this.index = startIndex;
    097
    098        final int len = Array.getLength(array);
    099        checkBound(startIndex, len, "start");
    100        checkBound(endIndex, len, "end");
    101        if (endIndex < startIndex) {
    102            throw new IllegalArgumentException("End index must not be less than start index.");
    103        }
    104    }
    105
    106    /**
    107     * Checks whether the index is valid or not.
    108     *
    109     * @param bound  The index to check
    110     * @param len  The length of the array
    111     * @param type  The index type (for error messages)
    112     * @throws IndexOutOfBoundsException if the index is invalid
    113     */
    114    protected void checkBound(final int bound, final int len, final String type) {
    115        if (bound > len) {
    116            throw new ArrayIndexOutOfBoundsException("Attempt to make an ArrayIterator that " + type + "s beyond the end of the array. ");
    117        }
    118        if (bound < 0) {
    119            throw new ArrayIndexOutOfBoundsException("Attempt to make an ArrayIterator that " + type + "s before the start of the array. ");
    120        }
    121    }
    122
    123    /**
    124     * Gets the array that this iterator is iterating over.
    125     *
    126     * @return The array this iterator iterates over.
    127     */
    128    public Object getArray() {
    129        return array;
    130    }
    131
    132    /**
    133     * Gets the end index to loop to.
    134     *
    135     * @return The end index
    136     * @since 4.0
    137     */
    138    public int getEndIndex() {
    139        return endIndex;
    140    }
    141
    142    /**
    143     * Gets the start index to loop from.
    144     *
    145     * @return The start index
    146     * @since 4.0
    147     */
    148    public int getStartIndex() {
    149        return startIndex;
    150    }
    151
    152    /**
    153     * Returns true if there are more elements to return from the array.
    154     *
    155     * @return true if there is a next element to return
    156     */
    157    @Override
    158    public boolean hasNext() {
    159        return index < endIndex;
    160    }
    161
    162    /**
    163     * Returns the next element in the array.
    164     *
    165     * @return The next element in the array
    166     * @throws NoSuchElementException if all the elements in the array
    167     *  have already been returned
    168     */
    169    @Override
    170    @SuppressWarnings("unchecked")
    171    public E next() {
    172        if (!hasNext()) {
    173            throw new NoSuchElementException();
    174        }
    175        return (E) Array.get(array, index++);
    176    }
    177
    178    /**
    179     * Always throws {@link UnsupportedOperationException}.
    180     *
    181     * @throws UnsupportedOperationException Always thrown.
    182     */
    183    @Override
    184    public void remove() {
    185        throw new UnsupportedOperationException("remove() method is not supported");
    186    }
    187
    188    /**
    189     * Resets the iterator back to the start index.
    190     */
    191    @Override
    192    public void reset() {
    193        index = startIndex;
    194    }
    195
    196}