Stream.iterate în Java

Crearea stream-urilor Java 8 (varianta cu condiție: Java 9)

Creează un stream din formule: iterate pornește de la o valoare și aplică un pas, generate cere fiecare valoare unui Supplier.

Sintaxă
static <T> Stream<T> iterate(T start, UnaryOperator<T> pas)
static <T> Stream<T> iterate(T start, Predicate<? super T> continua, UnaryOperator<T> pas)
static <T> Stream<T> generate(Supplier<? extends T> furnizor)

Ce face Stream.iterate

Stream.iterate(start, pas) produce start, pas(start), pas(pas(start)) și așa mai departe, la nesfârșit. Pentru a-l opri folosești limit(n) sau takeWhile.

Varianta cu trei argumente, iterate(start, conditie, pas), seamănă cu o buclă for: se oprește singură când condiția devine falsă. Este cea mai sigură variantă.

Stream.generate(furnizor) cere fiecare element unui Supplier, fără legătură cu elementul anterior: valori constante, numere aleatorii, citiri dintr-o sursă. Și acest stream este infinit, deci are nevoie de limit.

Parametri

Parametru Descriere
start Primul element.
continua Condiția verificată înaintea fiecărui element; când este falsă, stream-ul se oprește.
pas Funcția care calculează următorul element din cel curent.
furnizor Pentru generate: un Supplier chemat pentru fiecare element.

Ce returnează

Un Stream<T> infinit (sau finit, pentru varianta cu condiție).

Exemple

Exemplul 1: Puterile lui 2 și o buclă for cu stream

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        // infinit, oprit cu limit
        System.out.println(Stream.iterate(1, x -> x * 2).limit(10).toList());

        // ca un for (int i = 0; i < 20; i += 5)
        Stream.iterate(0, i -> i < 20, i -> i + 5)
                .forEach(i -> System.out.println("i = " + i));
    }
}

Rezultat

[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
i = 0
i = 5
i = 10
i = 15

Exemplul 2: Economii lunare cu dobândă

Fiecare element este calculat din cel anterior: suma crește cu 2% în fiecare lună.

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        Stream.iterate(1000.0, suma -> suma * 1.02)
                .limit(6)
                .forEach(suma -> System.out.printf("%.2f lei%n", suma));
    }
}

Rezultat

1000.00 lei
1020.00 lei
1040.40 lei
1061.21 lei
1082.43 lei
1104.08 lei

Exemplul 3: generate: valori care nu depind de cele anterioare

Cu un Random cu seed fix, numerele sunt aceleași la fiecare rulare. Fără seed ar fi altele de fiecare dată.

import java.util.Random;
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        System.out.println(Stream.generate(() -> "-").limit(10).toList());

        Random zar = new Random(7);
        System.out.println(Stream.generate(() -> zar.nextInt(1, 7)).limit(8).toList());
    }
}

Rezultat

[-, -, -, -, -, -, -, -, -, -]
[5, 3, 4, 5, 5, 5, 5, 6]

Greșeli frecvente

  • Uiți limit pe un stream infinit și apelezi toList() sau forEach. Programul rulează la nesfârșit sau rămâne fără memorie.
  • Pui filter în loc de condiția de oprire: iterate(1, x -> x + 1).filter(x -> x < 10) nu se oprește niciodată, pentru că filter doar sare peste elemente. Folosește varianta cu trei argumente sau takeWhile.

Comenzi înrudite

  • Stream.limit: limit păstrează doar primele n elemente, iar skip sare peste primele n.
  • Stream.takeWhile: takeWhile ia elemente cât timp condiția e adevărată și se oprește la primul care nu o respectă; dropWhile le sare pe acestea.
  • Supplier: Un „furnizor” de valori: nu primește nimic și returnează o valoare când apelezi get; util pentru valori create la nevoie.
  • UnaryOperator: O Function în care intrarea și ieșirea au același tip (T → T); folosită de List.replaceAll și Stream.iterate.
  • IntStream.range: Creează șirul de numere întregi dintre două limite: range fără ultima valoare, rangeClosed cu ea inclusă.