}
System.out.printi n();
}
public static void display(Collection<Pet> pets) { for(Pet p • pets)
System out print(p id() + " " + p + " "), System out printlnO.
}
public static void main(String[] args) {
List<Pet> petList = Pets arrayList(8).
Set<Pet> petSet = new HashSet<Pet>(petList). Map<String,Pet> petMap =
new LinkedHashMap<String.Pet>(). String[] names = ("Ralph. Eric, Robin. Lacey. " +
"Britney. Sam. Spot. Fluffy") splitC. "). for(int i = 0. i < names length. i++)
petMap.put(names[i]. petList get(i)). display(petList): display(petSet). display(petList iteratorO). displ ay (petSet iteratorO). System out println(petMap). System out. pri ntl n( petMap keySetO). displ ay (petMap valuesO). display(petMap.values О .iteratorO);
}
} /* Output-
0 Rat 1 Manx 2 Cymric 3.Mutt 4 Pug 5.Cymric 6 Pug 7 Manx 4:Pug 6 Pug 3 Mutt 1 Manx 5 Cymric 7 Manx 2:Cymric O-Rat O-Rat 1 Manx 2-Cymric 3-Mutt 4-Pug 5 Cymric 6 Pug 7 Manx 4-Pug 6 Pug 3 Mutt 1 Manx 5:Cymric 7.Manx 2 Cymric 0:Rat
{Ralph=Rat. Eric=Manx, Robin=Cymric. Lacey=Mutt. Britney=Pug. Sam=Cymric. Spot=Pug. Fluffy=Manx}
[Ralph. Eric. Robin. Lacey. Britney. Sam. Spot. Fluffy] 0:Rat l.Manx 2-Cymric 3-Mutt 4:Pug 5-Cymric 6:Pug 7 Manx 0:Rat 1 Manx 2-Cymric 3-Mutt 4.Pug 5:Cymric 6:Pug 7 Manx */// ~
Обе версии display() работают как с объектами Map, так и с подтипами Collection; при этом как Collection, так и Iterator изолируют методы display() от знания конкретной реализации используемого контейнера.
В данном случае два решения примерно равноценны. Использование Iterator становится предпочтительным при реализации постороннего класса, для которого реализация интерфейса Collection затруднена или нежелательна. Например, если мы создаем реализацию Collection наследованием от класса, содержащего объекты Pet, нам придется реализовать все методы Collection, даже если они не будут использоваться в методе display(). Хотя проблема легко решается наследованием от AbstractCollection, вам все равно придется реализовать iterator() вместе с size(), чтобы предоставить методы, не реализованные AbstractCollection, но используемые другими методами AbstractCollection:
// • hoidi ng/Col1ecti onSequence.java import typeinfo pets.*; import java.util.*;
public class CollectionSequence extends AbstractCollection<Pet> {
private Pet[] pets = Pets.createArray(8); public int sizeO { return pets.length; } public Iterator<Pet> iteratorO {
return new Iterator<Pet>() {
private int index = 0; public boolean hasNextO. {
return index < pets.length;
public Pet nextО { return pets[index++]; } public void removeО { // He реализован
throw new UnsupportedOperationExceptionO;
}
}:
}
public static void main(String[] args) {
CollectionSequence с = new Col 1ectionSequence(); InterfaceVsIterator.di splay(с); InterfaceVsIterator.di splay(c.i terator());
}
} /* Output:
0:Rat class="underline" Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx 0:Rat class="underline" Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx *///:-
Метод remove() является необязательной операцией. В нашем примере реа- лизовывать его не нужно, и в случае вызова он выдает исключение.
Из приведенного примера видно, что при реализации Collection вы также реализуете iterator(), а простая отдельная реализация iterator() требует чуть меньших усилий, чем наследование от AbstractCollection. Но, если класс уже наследует от другого класса, наследование еще и от AbstractCollection невозможно. В этом случае для реализации Collection придется реализовать все методы интерфейса, и тогда гораздо проще ограничиться наследованием и добавить возможность создания итератора:
//: hoidi ng/NonCol1ecti onSequence.java import typeinfo.pets.*; import java.util.*;
class PetSequence {
protected Pet[] pets = Pets.createArray(8);
}
public class NonCollectionSequence extends PetSequence { public Iterator<Pet> iteratorO {
return new Iterator<Pet>() {
private int index = 0; public boolean hasNextO {
return index < pets length;
}
public Pet nextO { return pets[index++]; } public void removeO { // He реализован
throw new UnsupportedOperationExceptionO;
}
}:
}
public static void main(String[] args) {
NonCollectionSequence nc = new NonCollectionSequence(); InterfaceVsIterator.display(nc.iteratorO);
}
} /* Output:
0:Rat class="underline" Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx *///:-
Создание Iterator обеспечивает минимальную логическую привязку между последовательностью и методом, использующим эту последовательность, а также налагает гораздо меньше ограничений на класс последовательности, реализующий Collection.
Синтаксис foreach и итераторы
До настоящего момента «синтаксис foreach» использовался в основном с массивами, но он также будет работать с любым объектом Collection. Некоторые примеры уже встречались нам при работе с ArrayList, но можно привести и более общее подтверждение:
//: holding/ForEachCollections java
// Синтаксис foreach работает с любыми коллекциями
import java.util.*,
public class ForEachCollections {
public static void main(String[] args) {
Collection<String> cs = new LinkedList<String>(); Col lections.addAl1(cs,
"Take the long way home".splitC' ")); for(String s : cs)
System, out. pri nt(.. + s + ...... ),
}
} /* Output-
'Take' 'the' 'long' 'way' 'home' *///:-
Поскольку cs является Collection, этот пример показывает, что поддержка foreach является характеристикой всех объектов Collection.
Работа этой конструкции объясняется тем, что в Java SE5 появился новый интерфейс Iterable, который содержит метод iterator() для создания Iterator, и именно интерфейс Iterable используется при переборе последовательности в синтаксисе foreach. Следовательно, создав любой класс, реализующий Iterable, вы сможете использовать его в синтаксисе foreach:
//: hoidi ng/IterableClass.java // Anything Iterable works with foreach. import java.util.*;
public class IterableClass implements Iterable<String> { protected StringE] words = ("And that is how " +
"we know the Earth to be banana-shaped.").splitC "); public Iterator<String> iteratorO {
return new Iterator<String>() { private int index = 0; public boolean hasNextO {
return index < words length;
}
public String nextO { return words[index++]; } public void remove0 { // Not implemented
throw new UnsupportedOperationExceptionO,
};
public static void main(Stnng[] args) {
for(String s • new IterableClassO) System out print(s + " ");
}
} /* Output.
And that is how we know the Earth to be banana-shaped. *///:-
Метод iterator() возвращает экземпляр анонимной внутренней реализации Iterator<string>, последовательно доставляющей каждое слово в массиве. В main() мы видим, что IterableClass действительно работает в синтаксисе foreach.
В Java SE5 многие классы реализуют Iterable, прежде всего все классы Collection (но не Map). Например, следующий код выводит все переменные окружения (environment) операционной системы:
//: holding/Envi ronmentVariables.java import java util *;
public class EnvironmentVariables {
public static void main(String[] args) {
for (Map Entry entry System getenvO .entrySetO) { System.out.println(entry.getKey() + ": " + entry. getValueO);
}
}
} /* (Выполните, чтобы увидеть результат) *///:-
System.getenv() возвращает Map, entrySet() создает Set с элементами Map.Entry, a Set поддерживает Iterable и поэтому может использоваться в цикле foreach.