Ogólny format pętli iteracyjnej:
for (T wartosc : kolekcja) {
// dla każdego elementu z kolekcji dostępnego
// pod zmienną wartosc typu T
// gdzie T jest typem generycznym
}
Powyższy zapis jest równoznaczny z uzyskaniem dla danej kolekcji iteratora (obiekt klasy Iterator<T>) oraz wykorzystania metod, które on udostępnia (np. hasNext(), next()).
Iterator<T> iterator = kolekcja.iterator();
while(iterator.hasNext()) {
T wartosc = iterator.next();
// dla każdego elementu z kolekcji dostępnego
// pod zmienną wartosc typu T
// gdzie T jest typem generycznym
}
Jak utworzyć klasę, która będzie umożliwiała nam przejście przez wszystkie elementy za pomocą czy to pętli iteracyjnej for czy też while? Odpowiedź jest stosunkowo prosta. Musimy zaimplementować w naszej klasie interfejs Iterable<T> ("powiadamia" on o tym, że naszą klasę można przeglądać). Interfejs ten posiada tylko jedną metodę: public Iterator<T> iterator();zwracającą referencję do obiektu klasy implementującej interfejs Iterator<T>. Interfejs ten posiada trzy metody:
public boolean hasNext(); // sprawdza czy są jeszcze elementy w kolekcji public T next(); // zwraca kolejny element public void remove(); // usuwa kolejny elementZazwyczaj implementuje się w pełni tylko dwie pierwsze metody. Trzecią zostawia się pustą (ma ona bezpośredni wpływ na zawartość kolekcji i nie ma sensu w ten sposób usuwać elementów, od tego powinny być metody dostępne w samej kolekcji). Zobaczmy prosty przykład wykorzystania interfejsu Iterable<T> na podstawie klasy Lista<T> odzwierciedlającej listę jednostronną jednokierunkową. Najpierw klasa pojedynczego węzła/elementu listy Wezel<T>.
/**
* Węzeł - element listy
* @author kodatnik.blogspot.com
*/
class Wezel<T> {
// pole przechowujące wartość znajdującą się w węźle
private T obiekt;
// referencja do następnego elementu listy
private Wezel<T> nastepny;
// konstruktor domyślny;
public Wezel() {
// wywołanie konstruktora dwuparametrowego)
this(null, null);
}
// konstruktor dwuparametrowy
// wartość oraz referencja do następnego węzła
public Wezel(T obiekt, Wezel<T> nastepny) {
this.obiekt = obiekt;
this.nastepny = nastepny;
}
// metoda zwraca referencję do następnego węzła
public Wezel<T> pobierzNastepny() {
return nastepny;
}
// metoda zwraca przechowywaną w węźle wartość
public T pobierzObiekt() {
return obiekt;
}
}
oraz klasa główna Lista<T>:// wykorzystujemy klasę Iterator z pakietu java.util import java.util.Iterator; /** * Przykład wykorzystania iteratora * Lista jednostronna jednokierunkowa * @author kodatnik.blogspot.com */ class ListaZaimplementowaliśmy w klasie interfejs Iterable<T> (metoda iterator()) oraz utworzyliśmy wewnętrzną prywatną klasę IteratorListy implementującą interfejs Iterator<T>. Sprawdźmy działanie naszej klasy:implements Iterable<T> { // pole przechowujące referencję do początku listy private Wezel<T> poczatek; // konstruktor bezparametrowy public Lista () { // ustawiamy początek na null (lista pusta) poczatek = null; } // metoda wstawia dane na początek listy public void wstawNaPoczatek(T dane) { // tworzymy nowy węzeł oraz ustawiamy // zmienną poczatek tak aby go wskazywała poczatek = new Wezel<T>(dane, poczatek); } // metoda usuwa element znajdujący się na początku listy // oraz zwraca referencję do niego public Wezel<T> usunZPoczatku() { // zapamiętujemy element z początku listy Wezel<T> temp = poczatek; // zmieniamy referencje początku listy // na następny element (pomijamy pierwszy) poczatek = poczatek.pobierzNastepny(); // zwracamy zapamiętaną referencję return temp; } // metoda zwraca referencję do obiektu klasy // implementującej interfejs Iterator<T> public Iterator<T> iterator() { // tworzymy nowy obiekt wewnętrznej klasy IteratorListy // i zwracamy jego referencję return new IteratorListy(); } // prywatna klasa wewnętrzna implementująca interfejs Iterator<T> private class IteratorListy implements Iterator<T> { // pole przechowujące referencję do pierwszego elementu naszej listy private Wezel<T> temp = poczatek; // metoda zwraca wartość logiczną czy są jeszcze elementy w kolekcji public boolean hasNext() { return temp != null; } // metoda zwraca wartość elementu przechowywanego w kolejnym węźle public T next() { // pobieramy wartość (obiekt typu T) T obiekt = temp.pobierzObiekt(); // przechodzimy na następny element listy temp = temp.pobierzNastepny(); // zwracamy wartość return obiekt; } // metoda usuwająca element z kolekcji public void remove() { // ciało metody puste (patrz opis) } } }
// wykorzystujemy klasę Iterator z pakietu java.util
import java.util.Iterator;
/**
* Test listy
* @author kodatnik.blogspot.com
*/
public class TestIteratora {
public static void main (String[] args) {
// tworzymy pierwszą listę (parametryzujemy typem String)
Lista<String> listaPierwsza = new Lista<String>();
// dodajemy elementy na początek listy
listaPierwsza.wstawNaPoczatek("Adam");
listaPierwsza.wstawNaPoczatek("Marek");
listaPierwsza.wstawNaPoczatek("Kasia");
// pobieramy iterator z listy
Iterator<String> iterator = listaPierwsza.iterator();
// dopóki są jeszcze elementy
while(iterator.hasNext()) {
// pobieramy je i wyświetlamy je na ekranie
System.out.println (iterator.next());
}
// tworzymy drugą listę (parametryzujemy typem Integer)
Lista<Integer> listaDruga = new Lista<Integer>();
// dodajemy elementy do początek listy
listaDruga.wstawNaPoczatek(10);
listaDruga.wstawNaPoczatek(45);
listaDruga.wstawNaPoczatek(83);
// w pętli iteracyjnej wyświetlamy po kolei wszystkie elementy
for (Integer wartosc: listaDruga) {
System.out.println (wartosc);
}
}
}
Uruchomiona aplikacja:Kasia Marek Adam 83 45 10Kiedy korzystać z iteratora? Wtedy gdy nasza klasa przechowuje większą liczbę takich samych elementów, mówiąc inaczej jest kolekcją jakiś elementów. Implementacja interfejsu Iterable<T> znacznie uprości obsługę takiej klasy.

2 Komentarze - Przeglądamy kolekcję - interfejs Iterable<T>
Dobry artykuł. Ma w sobie to czego brakuje reszcie czyli użycie generyków. :)
nie ma to jak dobry blog
Prześlij komentarz
Możesz użyć niektórych tagów HTML, takich jak <b>, <i>, <u>, <a> Nie spamuj :)