javaintermediate

Custom Iterator and Iterable

Implement custom iterators and iterables for specialized data traversal and lazy sequence generation.

java
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

public class CustomIterators {

    // Range iterator (lazy)
    static class Range implements Iterable<Integer> {
        private final int start, end, step;

        Range(int start, int end, int step) {
            this.start = start;
            this.end = end;
            this.step = step;
        }

        static Range of(int start, int end) { return new Range(start, end, 1); }
        static Range of(int start, int end, int step) { return new Range(start, end, step); }

        @Override
        public Iterator<Integer> iterator() {
            return new Iterator<>() {
                private int current = start;
                public boolean hasNext() { return current < end; }
                public Integer next() {
                    if (!hasNext()) throw new NoSuchElementException();
                    int val = current;
                    current += step;
                    return val;
                }
            };
        }

        // Support streams
        public Stream<Integer> stream() {
            return StreamSupport.stream(spliterator(), false);
        }
    }

    // Fibonacci iterator (infinite)
    static class Fibonacci implements Iterable<Long> {
        @Override
        public Iterator<Long> iterator() {
            return new Iterator<>() {
                private long a = 0, b = 1;
                public boolean hasNext() { return true; }
                public Long next() {
                    long result = a;
                    long temp = a + b;
                    a = b;
                    b = temp;
                    return result;
                }
            };
        }

        public Stream<Long> stream() {
            return StreamSupport.stream(spliterator(), false);
        }
    }

    // Window/sliding iterator
    static <T> Iterator<List<T>> sliding(List<T> list, int windowSize) {
        return new Iterator<>() {
            private int pos = 0;
            public boolean hasNext() { return pos + windowSize <= list.size(); }
            public List<T> next() {
                if (!hasNext()) throw new NoSuchElementException();
                List<T> window = list.subList(pos, pos + windowSize);
                pos++;
                return window;
            }
        };
    }

    // Generate from function
    static <T> Iterable<T> generate(T seed, UnaryOperator<T> next, Predicate<T> hasNext) {
        return () -> new Iterator<>() {
            private T current = seed;
            public boolean hasNext() { return hasNext.test(current); }
            public T next() {
                T val = current;
                current = next.apply(current);
                return val;
            }
        };
    }

    public static void main(String[] args) {
        // Range
        for (int i : Range.of(0, 10, 2)) {
            System.out.print(i + " "); // 0 2 4 6 8
        }
        System.out.println();

        // Fibonacci
        new Fibonacci().stream()
            .limit(10)
            .forEach(n -> System.out.print(n + " ")); // 0 1 1 2 3 5 8 13 21 34
        System.out.println();

        // Sliding window
        var list = List.of(1, 2, 3, 4, 5);
        sliding(list, 3).forEachRemaining(System.out::println);

        // Powers of 2
        for (long n : generate(1L, x -> x * 2, x -> x < 1000)) {
            System.out.print(n + " "); // 1 2 4 8 ... 512
        }
    }
}

Use Cases

  • Lazy sequence generation for large datasets
  • Sliding window algorithms
  • Custom traversal patterns for domain objects

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.