Поиск…


Вступление

java.util.Iterator является стандартным интерфейсом Java SE для объекта, реализующего шаблон проектирования Iterator. Интерфейс java.lang.Iterable предназначен для объектов, которые могут предоставить итератор.

замечания

Можно выполнить итерацию по массиву с использованием цикла for -each, хотя массивы java не реализуют Iterable; итерация выполняется с помощью JVM с использованием недопустимого индекса в фоновом режиме.

Использование цикла Iterable in for

Классы, реализующие интерфейс Iterable<> могут использоваться for циклов. Это на самом деле только синтаксический сахар для получения итератора от объекта и использования его для получения всех элементов последовательно; он делает код более понятным, быстрее записывать конец, менее подверженный ошибкам.

public class UsingIterable {

    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(1,2,3,4,5,6,7);
        
        // List extends Collection, Collection extends Iterable
        Iterable<Integer> iterable = intList;
        
        // foreach-like loop
        for (Integer i: iterable) {
            System.out.println(i);
        }
        
        // pre java 5 way of iterating loops
        for(Iterator<Integer> i = iterable.iterator(); i.hasNext(); ) {
            Integer item = i.next();
            System.out.println(item);
        }
    }
}

Использование исходного итератора

Хотя использование цикла foreach (или «расширенный для цикла») прост, иногда полезно использовать итератор напрямую. Например, если вы хотите вывести кучу разделенных запятыми значений, но не хотите, чтобы последний элемент имел запятую:

List<String> yourData = //...
Iterator<String> iterator = yourData.iterator();
while (iterator.hasNext()){
    // next() "moves" the iterator to the next entry and returns it's value.
    String entry = iterator.next();
    System.out.print(entry);
    if (iterator.hasNext()){
        // If the iterator has another element after the current one:
        System.out.print(",");
    }
}

Это намного проще и понятнее, чем наличие переменной isLastEntry или выполнение вычислений с индексом цикла.

Создание собственного Iterable.

Чтобы создать свой собственный Iterable, как с любым интерфейсом, вы просто реализуете абстрактные методы в интерфейсе. Для Iterable существует только один, который называется iterator() . Но его возвращаемый тип Iterator сам по себе является интерфейсом с тремя абстрактными методами. Вы можете вернуть итератор, связанный с какой-либо коллекцией, или создать собственную собственную реализацию:

public static class Alphabet implements Iterable<Character> {

    @Override
    public Iterator<Character> iterator() {
        return new Iterator<Character>() {
            char letter = 'a';

            @Override
            public boolean hasNext() {
                return letter <= 'z';
            }

            @Override
            public Character next() {
                return letter++;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("Doesn't make sense to remove a letter");
            }
        };
    }
}

Использовать:

public static void main(String[] args) {
    for(char c : new Alphabet()) {
        System.out.println("c = " + c);
    }
}

Новый Iterator должен иметь состояние, указывающее на первый элемент, каждый вызов следующего обновляет его состояние, чтобы указать на следующий. Функция hasNext() проверяет, находится ли итератор в конце. Если итератор был связан с изменяемой коллекцией, то может быть реализован необязательный метод remove() итератора, чтобы удалить элемент, указанный в настоящее время из базовой коллекции.

Удаление элементов с помощью итератора

Метод Iterator.remove() является необязательным методом, который удаляет элемент, возвращенный предыдущим вызовом, в Iterator.next() . Например, следующий код заполняет список строк, а затем удаляет все пустые строки.

List<String> names = new ArrayList<>();
names.add("name 1");
names.add("name 2");
names.add("");
names.add("name 3");
names.add("");
System.out.println("Old Size : " + names.size());
Iterator<String> it = names.iterator();
while (it.hasNext()) {
  String el = it.next();
  if (el.equals("")) {
    it.remove();
  }
}
System.out.println("New Size : " + names.size());

Выход :

Old Size : 5
New Size : 3

Обратите внимание, что приведенный выше код является безопасным способом удаления элементов при повторении типичной коллекции. Если вместо этого вы пытаетесь удалить элементы из коллекции следующим образом:

for (String el: names) {
    if (el.equals("")) {
        names.remove(el); // WRONG!
    }
}

типичная коллекция (такая как ArrayList ), которая предоставляет итераторам с быстрой семантикой итератора с ошибкой, выдает исключение ConcurrentModificationException .

Метод remove() может вызываться только один раз после next() вызова next() . Если он вызывается перед вызовом next() или если он вызывается дважды после вызова next() вызов remove() будет вызывать IllegalStateException .

Операция remove описывается как необязательная операция; т.е. не все итераторы это позволят. Примеры, в которых он не поддерживается, включают в себя итераторы для неизменных коллекций, представления только для чтения коллекций или коллекции фиксированного размера. Если remove() вызывается, когда итератор не поддерживает удаление, он UnsupportedOperationException исключение UnsupportedOperationException .



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow