Как сделать класс итератор для другого класса
Есть класс, расширяющий 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