Ce face Iteratori și for-each
Bucla for-each (for (String oras : orase)) dă pe rând fiecare element, fără indice. Funcționează cu array-uri și cu orice obiect care implementează Iterable (toate colecțiile: List, Set, cheile unui Map).
În spate, pentru colecții, compilatorul folosește un Iterator: un obiect cu hasNext() (mai sunt elemente?) și next() (dă următorul element). Poți folosi iteratorul direct când ai nevoie de remove(), singura metodă sigură de a șterge elemente în timpul parcurgerii.
Clasele tale pot fi folosite în for-each dacă implementează Iterable<T>, adică au o metodă iterator(). Variabila din for-each este o copie: atribuirea ei nu modifică array-ul sau colecția.
Exemple
Exemplul 1: Parcurgerea unui array, a unei liste și a unui Map
Același tip de buclă merge peste array-uri și colecții. Pentru Map parcurgi entrySet() (sau keySet() / values()).
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
int[] note = {9, 7, 10};
int suma = 0;
for (int nota : note) {
suma += nota;
}
System.out.println("suma notelor: " + suma);
List<String> orase = List.of("Iași", "Cluj", "Timișoara");
for (String oras : orase) {
System.out.println("- " + oras);
}
Map<String, Integer> stoc = new TreeMap<>(Map.of("mere", 40, "pere", 12));
for (Map.Entry<String, Integer> e : stoc.entrySet()) {
System.out.println(e.getKey() + ": " + e.getValue() + " kg");
}
}
}
Rezultat
suma notelor: 26
- Iași
- Cluj
- Timișoara
mere: 40 kg
pere: 12 kg
Exemplul 2: Ștergere în timpul parcurgerii cu Iterator
remove() din for-each aruncă ConcurrentModificationException. Cu iteratorul, it.remove() șterge elementul curent în siguranță.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> note = new ArrayList<>(List.of(9, 4, 10, 3, 7));
try {
for (Integer n : note) {
if (n < 5) {
note.remove(n);
}
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("for-each + remove: ConcurrentModificationException");
}
note = new ArrayList<>(List.of(9, 4, 10, 3, 7));
Iterator<Integer> it = note.iterator();
while (it.hasNext()) {
if (it.next() < 5) {
it.remove();
}
}
System.out.println("doar note de trecere: " + note);
}
}
Rezultat
for-each + remove: ConcurrentModificationException
doar note de trecere: [9, 10, 7]
Exemplul 3: O clasă proprie folosită în for-each
Interval implementează Iterable<Integer>, deci poate apărea după : într-un for-each. Iteratorul ține minte poziția curentă.
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Main {
record Interval(int start, int sfarsit, int pas) implements Iterable<Integer> {
public Iterator<Integer> iterator() {
return new Iterator<>() {
private int curent = start;
public boolean hasNext() {
return curent <= sfarsit;
}
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
int valoare = curent;
curent += pas;
return valoare;
}
};
}
}
public static void main(String[] args) {
for (int ora : new Interval(8, 20, 4)) {
System.out.println("autobuz la ora " + ora + ":00");
}
}
}
Rezultat
autobuz la ora 8:00
autobuz la ora 12:00
autobuz la ora 16:00
autobuz la ora 20:00
Greșeli frecvente
- Ștergerea sau adăugarea de elemente în colecție în timpul unui for-each:
ConcurrentModificationException. FoloseșteIterator.removesauremoveIf. - Așteptarea ca
for (int n : note) n = 0;să modifice array-ul:neste o copie. - Apelarea lui
next()de două ori într-un pas al buclei: sari peste elemente.
Comenzi înrudite
for: Bucla clasică cu contor: inițializare, condiție verificată înaintea fiecărui pas și actualizare după fiecare pas.Array-uri: Un array păstrează un număr fix de elemente de același tip, accesate prin indice de la 0 la length – 1.Generics (tipuri generice): Generics parametrizează clase și metode cu tipuri (List<String>, Map<String, Integer>), ca erorile de tip să apară la compilare, nu la rulare.Stream-uri (ideea): Un stream descrie o prelucrare de date ca un lanț: sursă, operații intermediare (filter, map, sorted) și o operație finală (toList, count, collect).Clase interne și anonime: O clasă poate fi declarată în altă clasă (statică sau interioară), într-o metodă (locală) sau direct la folosire, fără nume (anonimă).