92

92


Один из доводов в пользу интерфейсов заключается в том, что они позволя­ют создавать более универсальный код. Код, написанный для интерфейса, а не для его реализации, может быть применен к более широкому кругу объектов. Таким образом, если я пишу метод, которому при вызове передается Collection, этот ме­тод будет работать с любым типом, реализующим Collection, — следовательно, если новый класс реализует Collection, он будет совместим с моим методом. Од­нако интересно заметить, что стандартная библиотека С++ не имеет общего ба­зового класса для своих контейнеров — вся общность контейнеров обеспечива­ется итераторами. Казалось бы, в Java будет логично последовать примеру С++ и выражать сходство между контейнерами при помощи итераторов, а не Collection. Тем не менее эти два подхода взаимосвязаны, потому что реализация Collection также означает поддержку метода iterator():

//: hoiding/InterfaceVsIterator.java import typeinfo pets *, import java.util.*,

public class InterfaceVsIterator {

public static void display(Iterator<Pet> it) {. whileCit hasNextO) {

Pet p = it.nextO.

System out pri nt(p id() + " " + p + " ").

}

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 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 обеспечивает минимальную логическую привязку между последовательностью и методом, использующим эту последовательность, а так­же налагает гораздо меньше ограничений на класс последовательности, реали­зующий Collection.

Синтаксис foreach и итераторы

До настоящего момента «синтаксис foreach» использовался в основном с масси­вами, но он также будет работать с любым объектом Collection. Некоторые при­меры уже встречались нам при работе с ArrayList, но можно привести и более об­щее подтверждение:

//: holding/ForEachCollections java

// Синтаксис foreach работает с любыми коллекциями

import java.util.*,

public class ForEachCollections {

public static void main(String[] args) {

Report Page