Философия Java3
Шрифт:
Обе версии display работают как с объектами Map, так и с подтипами Collection; при этом как Collection, так и Iterator изолируют методы display от знания конкретной реализации используемого контейнера.
В данном случае два решения примерно равноценны. Использование Iterator становится предпочтительным при реализации постороннего класса, для которого реализация интерфейса Collection затруднена или нежелательна. Например, если мы создаем реализацию Collection наследованием от класса, содержащего объекты Pet, нам придется реализовать все методы Collection,
// • 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 l:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx 0:Rat l: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 l:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx *///:-
Создание Iterator
Синтаксис 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) операционной системы: