ArrayIndexOutOfBoundsException при перечислении массива в итераторе с увеличением шага перечисления

У нас есть массив на 400 чисел: 0, 0.5,...199.5, 200. В итераторе этот массив перебирается и, в зависимости от указанной в main скорости перечисления (speed), меняется шаг итерации. Speed - число, которое будет прибавляться в классе-итераторе к index, от чего будет зависеть шаг перебора. Далее в консоль должен выводиться этот массив, но с другим шагом. Если в классе-итераторе указать return pointList[index++], то с итерацией проблем нет, но, при указании любого speed, даже равного 1, программа выкидывает ArrayIndexOutOfBoundsException: 400 и указывает, что ошибка в строке класса-итератора:return pointList[index += speed] и в main в строке System.out.println(iterator.next()); Вот сижу, туплю, не могу разобраться, в чём дело. Поэтому, пожалуйста, дайте каких-нибудь наводок или намеков, в чем может быть проблема?

Полный код итератора:

public class PointIterator<Double> implements Iterator<Double> {
private int index;
private int speed;
private Double[] pointList;

public PointIterator(Double[] pointList){
    this.pointList = pointList;
}

public boolean hasNext() {
    if(index < pointList.length){
        return true;
    }else {
        return false;
    }
}

public Double next() {
    if(this.hasNext()) {
        return pointList[index += speed];
    }else {
        throw new NoSuchElementException();
    }
}

public void changeSpeed(int speed){
    this.speed = speed;

Фрагмент кода из main:

PointIterator iterator = harmonica.iterator(); //в классе Harmonica создаётся массив на 400 элементов и реализуется итератор, в нём проблем не наблюдается.
        iterator.changeSpeed(1); //сюда передаётся наше значение speed
        System.out.println("Array's length: " + harmonica.getPositionLength() + "\n");
        while (iterator.hasNext()){
            System.out.println(iterator.next());                
        }

Ответы (3 шт):

Автор решения: Alexey R.

Здесь

public boolean hasNext() {
    if(index < pointList.length){
        return true;
    }else {
        return false;
    }
}

hasNext() будет возвращать true когда следующего элемента уже не будет. Например массив размером 10. Его последний индекс 9.

hasNext() для индекса 9 вернет true, потому что 9 < 10, не смотря что элементов с индексом большим 9 не существует.

Кроме того, при определении наличия следующего элемента необходимо также учитывать шаг.

→ Ссылка
Автор решения: Дмитрий

Вообще так делать нельзя. Разумеется, вы можете задать шаг (скорость). Проблема в том, метод next в итераторе не должен ничего проверять. Он должен возвращать следующий элемент. Для прверки есть метод hasNext. А теперь представьте ситуацию классического использования итератора :

while(iterator.hasNext()){
   //здесь я меняю шаг
   iterator.next();
}

В этом случае hasNext уже вернул true, для этого ему нужно знать шаг, однако в цикле вы его изменили (после проверки). Рано или поздно вы получите исключение. Мало того, ваши коллеги за такую "имплементацию" точно спасибо не скажут. Все знают, что такое итератор и каково его ожидаемое поведение. Поэтому имплементация итератора должна быть примерно такой:

import java.util.Iterator;

public class PointIterator<Double> implements Iterator<Double> {

    private int cursor = 0;
    private int step;
    private int stepChanges;
    private final Double[] array;

    public PointIterator(Double[] array, int step) {
        this.step = step;
        this.stepChanges = step;
        this.array = array;
    }

    @Override
    public boolean hasNext() {
        step = stepChanges;
        return cursor + step < array.length;
    }

    @Override
    public Double next() {
        Double next = array[cursor];
        cursor += step;
        return next;
    }
    
    public void changeSpeed(int step){
        this.stepChanges = step;
    }
    
}
→ Ссылка
Автор решения: Сабир Исламов

Помимо того, что hasNext() имеет не верное условие, о чем сказали в другом ответе, ещё и метод делает проверку без учета текущего шага, что может привести к вылету за пределы массива на этапе работы метода next() в момент внутренней проверки:

 if(this.hasNext()) {
        return pointList[index += speed];
 }

Что в общем-то можно исправить если уж делаете класс-обертку в методе hasNext(), но опять таки это действительно очень не интуитивная реализация метода.

→ Ссылка