Как сделать класс итератор для другого класса
Есть класс, расширяющий Iterable<Integer>, по которому мы будем итерироваться.
В процессе итерирования мы будем от него получать случайные числа в диапазоне значений.
Диапазон задаётся двумя числами - минимальным и максимальным значениями. Как создать класс итератор?
public class Randoms implements Iterable<Integer> {
protected int min, max;
public Randoms(int min, int max) {
this.min = min;
this.max = max;
}
@Override
public Iterator<Integer> iterator() {
// ???
}
}
Ответы (1 шт):
Поскольку в первоначальном коде данной реализации интерфейса Iterable было приведено поле-итератор по примитивам int PrimitiveIterator.OfInt, то можно создать и вернуть это поле в качестве требуемого итератора.
Варианты реализации могут отличаться в зависимости от задания.
Например, если данная реализация Iterable<Integer> возвращает бесконечную последовательность, метод hasNext соответствующего итератора должен всегда возвращать true, а метод nextInt может использовать метод соответствующего класса-наследника Random.
Например, существует метод ThreadLocalRandom::nextInt(int origin, int bound), позволяющий получить случайное число в заданном диапазоне.
Тогда полная реализация Randoms может выглядеть так:
class Randoms implements Iterable<Integer> {
protected ThreadLocalRandom random = ThreadLocalRandom.current();
protected PrimitiveIterator.OfInt randomIt = new PrimitiveIterator.OfInt() {
@Override
public boolean hasNext() {
return true;
}
@Override
public int nextInt() {
return random.nextInt(min, max);
}
};
protected int min, max;
public Randoms(int min, int max) {
this.min = min;
this.max = max + 1; // чтобы включить `max` в диапазон
}
@Override
public Iterator<Integer> iterator() {
return randomIt;
}
}
Также хотел бы обратить внимание, что для того, чтобы сгенерировать последовательность случайных чисел, совершенно не обязательно писать свои реализации Iterable / Iterator / PrimitiveIterator.
В классе Random и его наследниках есть методы, возвращающие стримы случайных целых чисел IntStream в заданном диапазоне:
Random::ints(int randomNumberOrigin, int randomNumberBound)-- условно "неограниченный" поток случайных чисел (на самом деле, количество элементов ограничено константойLong.MAX_VALUE, т.е. 263 - 1).Random::ints(long streamSize, int randomNumberOrigin, int randomNumberBound)-- количество элементов в потоке ограничено.
Таким образом, получить бесконечные последовательности случайных чисел в заданном диапазоне (например, [10, 40]) можно по-разному:
Iterable<Integer> myRandoms = new Randoms(10, 40); // 40 inclusive
IntStream streamRandoms = new Random().ints(10, 41); // 40 exclusive, adding 1