Java - cyklus for-each

Iterování kolekcí je horší než je nutné. Zvažte následující metodu, která obsahuje kolekci úloh časovače a ruší je:

	void cancelAll(Collection&ls;TimerTask> c) {
		for (Iterator<TimerTask> i = c.iterator(); i.hasNext();)
			i.next().cancel();
	}

Iterátor je zdrojem zmatku. Více než to, je příležitostí udělat chybu. Proměnná iterátoru se objevuje ve smyčce třikrát: to znamená dva zdroje chyb. Konstrukce for - each se vyhýbá zmatku a tím i možnosti udělat chybu. Takto vypadá příklad s konstrukcí for - each:

	void cancelAll(Collection<TimerTask> c) {
		for (TimerTask t : c)
			t.cancel();
	}

Když uvidíte dvojtečku (:), čtěte ji jako "v". Smyčku výše bychom přečetli jako "pro každou TimerTask t v c". Jak vidíte, konstrukce for - each jde krásně dohromady s generickými datovými typy. Zachovává typovou bezpečnost ale zárove� odstra�uje všechen ten zmatek. Protože nemusíte deklarovat iterátor, nemusíte pro něj poskytovat generickou deklaraci (kompilátor to udělá za vás bez vašeho vědomí, ale nemusíte se kvůli tomu znepokojovat).

Zde je běžná chyba kterou lidé dělají když se snaží vhnízdit druhý cyklus při iteraci dvěma kolekcemi:

	List suits = ...;
	List ranks = ...;
	List sortedDeck = new ArrayList();

	// NEFUNGUJE - vyhazuje výjimku NoSuchElementException
	for (Iterator i = suits.iterator(); i.hasNext();)
		for (Iterator j = ranks.iterator(); j.hasNext();)
			sortedDeck.add(new Card(i.next(), j.next()));

Dokážete najít chybu? Nevadí pokud ji nenajdete. Mnoho programátorských expertů dělá tuto chybu znovu a znovu. Problém je že metoda next je volána příliš často ve "vnější" kolekci (suits0. Je volána ve vhnízděném cyklu jak pro vnější tak vnitřní kolekci, což je špatně. Abychom to opravili, musíme přidat proměnnou suit v platnosti rozssahu vnějšího cyklu:

	// Opraveno, ale nešikovně
	for (Iterator i = suits.iterator(); i.hasNext();) {
		Suit suit = (Suit) i.next();
		for (Iterator j = ranks.iterator(); j.hasNext();)
			sortedDeck.add(new Card(suit, j.next()));
	}

Takže jak se tohle všechno dá zvládnout pomocí cyklu for - each? Je jako stvořený pro vhnízděné cykly! Paste se pohledem:

	for (Suit suit : suits)
		for (rank rank : ranks)
			sortedDeck.add(new Card(suit, rank));

Cyklus for - each také můžeme použít s poli, kde skrývá proměnnou indexu pole místo iterátoru. Následujíc metoda vrací součet hodnot v poli int:

	// Vrací součet prvků v poli a
	int sum(int�[ a) {
		int result = 0;
		for (int i : a)
			result += i;
		return result;
	}

Takže kdy byste měli použít cyklus for - each? Kdykoli můžete. Opravdu zkrášlí váš kód. Naneštěstí jej nemůžete použít kdekoli. Zvažte npaříklad metodu expurgate. Program potřebuje přístup k iterátoru aby mohl odstranit daný prvek. Cykus for - each skrývá iterátor, čili nemůžete volat metodu remove. takže cyklus for - each není použitelný pro filtrování. Podobně není použitelný v cyklech kde potřebujete nahradit prvky v seznamu nebo poli které procházíte. A nakonec není použitelný pro procházení více kolekcemi zárove�. Tato omezení byla návrhářům známa a jejich cílem bylo přijít s čistou, jednoduchou konstrukcí která pokryje většinu případů použití.