Java #48: własny iterator (interfejs Iterable)

Własny iterator

Skoro znasz zarówno typy generyczne jak i struktury danych, to możesz napisać swój własny iterator, który będzie przechodził po kolekcji, zgodnie z Twoją intencją. Wpierw należy zaimplementować interfejs Iterator, który zawiera dwie metody hasNext i next. Pierwsza z nich musi zwracać warunek logiczny prawda-fałsz, decydujący kiedy przerwać pętle. Druga metoda powinna decydować w jaki sposób będzie iterowana kolekcja. Do tego najłatwiej stworzyć sobie jakieś pole (w moim przypadku jest to cursor), które będzie trzymać numer elementu, który został właśnie przetworzony.

U mnie dodatkowo, aby mój własny iterator czymś się różnił od standardowego, przetwarzam co drugi element kolekcji. Pamiętaj, że poniższy kod nie jest bezpieczny wątkowo. Klasa korzysta też ze znanego Tobie typu generycznego, dzięki czemu iterator zadziała podobnie dla każdej listy, jaką utworzysz.

Implementacja modelu korzystając z interfejsu Iterator

public class MyIterator<T> implements Iterator<T>{
	private Integer cursor = 0;
	private List<T> list;
    
    public MyIterator(List<T> list) {
        this.list = list;
    }
	@Override
	public boolean hasNext() {
		return cursor < list.size();
	}
	@SuppressWarnings("unchecked")
	@Override
	public T next() {
		if (!hasNext()) {
			throw new NoSuchElementException();
		}
		@SuppressWarnings("unchecked")
		T value = (T) list.get(cursor);
		cursor = cursor + 2;
		return value;
	}
}

Kolejnym krokiem jest zaimplementowanie swojej kolekcji. W moim przypadku jest nią klasa MyList, która nie różni się niczym o zwykłej listy, poza użyciem wcześniej zdefiniowanego iteratora. MyList musi implementować interfejs Iterable, który zawiera sygnaturę metody iterator znanej Ci z poprzedniego ćwiczenia. Zawieram w niej wywołanie napisanego przeze mnie iteratora, ale zamiast T wstawiam konkretną klasę, która jestem typem reprezentującym elementy mojej listy (u mnie jest to Integer). Dodatkowo w konstruktorze podaję wyliczaną za pomocą metody size długość listy.

Użycie własnego iteratora

public class MyList implements Iterable<Integer> {
	 private List<Integer> list;
	 MyList(List<Integer> list) {
	  this.list = list;
	 }
	 public Iterator<Integer> iterator() {
	  return new MyIterator<>(list.size());
	 }
}

Teraz wystarczy skorzystać z wyżej utworzonej listy w metodzie main. Mój własny iterator pozwoli mi w tym przypadku przeglądać liczby z ciągu fibonacciego.

public class IteratorMain {
	public static void main(String[] args) {
		List<Integer> fibonacci = new ArrayList<>();
		fibonacci.add(0);
		fibonacci.add(1);
		fibonacci.add(1);
		fibonacci.add(2);
		fibonacci.add(3);
		fibonacci.add(5);
		fibonacci.add(8);
		
		System.out.println("Przeglad ciagu fibonacciego za pomoca zwyklej petli:");
		fibonacci.forEach(x -> System.out.println(x));
		
		MyList myList = new MyList(fibonacci);
		System.out.println("Przeglad ciagu fibonacciego za pomoca nowego iteratora:");
		Iterator<Integer> iterator = myList.iterator();
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

W powyższym przykładzie stworzyłem ciąg Fibonacciego korzystając z tablicy dynamicznej. Nie jest to oczywiście najlepsza struktura dla takiego ciągu danych, ale dzięki temu zobaczysz, że faktycznie jest ona iterowana co dwa elementy.

Przeglad ciagu fibonacciego za pomoca zwyklej petli:
0
1
1
2
3
5
8
Przeglad ciagu fibonacciego za pomoca nowego iteratora:
0
1
3
8

I to wszystko! Teraz już wiesz, jak napisać własny iterator, w przypadku gdy standardowy nie jest wystarczający.

Lekcja o podstawach iteratora: Java średnio zaawansowane #19: interfejs Iterator

Link do kodu: https://github.com/developeronthego/java-advanced/tree/master/src/main/java/advanced/lesson4

Stay in the Loop

Get the daily email from CryptoNews that makes reading the news actually enjoyable. Join our mailing list to stay in the loop to stay informed, for free.

Ostatnio dodane

- Advertisement - spot_img

Powiązane wpisy