Интерфейс Iterator

 

В 70—80-х годах прошлого столетия, после того как была осознана важность правильной организации данных в определенную структуру, большое внимание уделялось изучению’ и’ Построению различных структур данных: связанных списков, очередей, деков, стеков, деревьев, сетей

Вместе c развитием структур данных развивались и алгоритмы работы с ними: сортировка, поиск, обход, хэширование.

Этим вопросам посвящена Обширная литература, посмотрите, например, книгу [11]. ‘

В 90-х годах было решено заносить данные в определенную коллекцию, скрыв ее внутреннюю структуру, а для работы с данными использовать методы этой коллекции.

В частности, задачу обхода возложили на саму коллекцию. В Java API введен интерфейс iterator , описывающий способ обхода всех элементов коллекции. В каждой коллекции есть метод iterator (), возвращающий реализацию интерфейса iterator для указанной коллекции. Получив эту реализацию, можно обходить коллекцию в некотором порядке, определенном данным итератором, с помощью методов, описанных в интерфейсе iterator и реализованных в этом итераторе. Подобная техника использована в классе

StringTokenizer.

В интерфейсе iterator описаны всего три метода:

логический метод hasNext () возвращает true , если обход еще не завершен;

метод next о делает текущим следующий элемент коллекции и возвращает его в виде объекта класса object ;

метод remove о удаляет текущий элемент коллекции.

Можно представить себе дело так, что итератор — это указатель на элемент коллекции. При создании итератора указатель устанавливается перед первым элементом, метод next () перемещает указатель на первый элемент и показывает его. Следующее применение метода next () перемещает указатель на второй элемент коллекции и показывает его. Последнее применение метода next () выводит указатель за последний элемент коллекции.

Метод remove (), пожалуй, излишен, он уже не относится к задаче обхода коллекции, но позволяет при просмотре коллекции удалять из нее ненужные элементы.

В листинге 6.5 к тексту листинга 6.1 добавлена работа с итератором.

 

 Листинг 6.5. Использование итератора вектора 

Vector v = new Vector();

String s = «Строка, которую мы хотим разобрать на слова.»; 

StringTokenizer st = new StringTokenizer(s, » \t\n\r,.»); 

while (st.hasMoreTokens()){

     // Получаем слово и заносим в вектор.

     v.add(st.nextToken());                                 // Добавляем в конец вектора }

System.out.print*Ln(v.firstElement(});                      // Первый элемент 

System.out.println(v.lastElement());                        // Последний элемент 

v.setSize(4);                                               // Уменьшаем число элементов

  v.add(«собрать.»);                                         // Добавляем в конец укороченного вектора 

v.set(3, «опять»);                                          // Ставим в позицию 3

for (int i = 0; i < v.sizeO; i++)                           // Перебираем весь вектор

System.out.print(v.get(i) + «.»); 

System.out.println(};

Iterator it = v.iterator ();                                // Получаем итератор вектора 

try{

    while(it.hasNext())                                     // Пока в векторе есть элементы,

        System.out.println(it.next());           // выводим текущий элемент 

}catch(Exception e){}

 

Интерфейс Listlterator

 

Интерфейс Listiterator расширяет интерфейс iterator , обеспечивая перемещение по коллекции как в прямом, так и в обратном направлении. Он может быть реализован только в тех коллекциях, в которых есть понятия следующего и предыдущего элемента и где элементы пронумерованы.

В интерфейс Listiterator добавлены следующие методы:

void add (Object element) — добавляет элемент element перед текущим элементом;

boolean hasPrevious () — возвращает true , если в коллекции есть элементы, стоящие перед текущим элементом;

int nextindex() — возвращает индекс текущего элемента; если текущим является последний элемент коллекции, возвращает размер коллекции;

Object previous () — возвращает предыдущий элемент и делает его текущим;

int previous index () — возвращает индекс предыдущего элемента;

void set (Object element) — заменяет текущий элемент элементом element;

выполняется сразу после next () или previous ().

Как видите, итераторы могут изменять коллекцию, в которой они работают, добавляя, удаляя и заменяя элементы. Чтобы это не приводило к конфликтам, предусмотрена исключительная ситуация, возникающая при попытке использования итераторов параллельно «родным» методам коллекции. Именно поэтому в листинге 6.5 действия с итератором заключены в блок tryUcatch(){} .

Изменим окончание листинга 6.5 с использованием итератора Listiterator .

// Текст листинга 6.1…

// …

Listiterator lit = v.listlterator();                       // Получаем итератор вектора

                 // Указатель сейчас находится перед началом вектора 

try{

   while(lit.hasNext())                                   // Пока в векторе есть элементы

      System.out.println(lit.next());                     // Переходим к следующему 

                                                          // элементу и выводим его

         // Теперь указатель за концом вектора. Пройдем к началу

while (lit. hasPrevious ()) 

       System, out. printlnf lit. previblis ()); :

}catch (Exception e) ()

Интересно, что повторное применение методов next () и previous () друг за другом будет выдавать один и тот же текущий элемент. : Посмотрим теперь, какие возможности предоставляют классы-коллекции Java 2.