Java Language
Итератор и Итерабель
Поиск…
Вступление
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
.