Обратный итератор в Java: применение синтаксиса for each
Быстрый ответ
Для реализации обратного for-each
цикла потребуется с использованием ListIterator
. Пример:
List<String> list = Arrays.asList("a", "b", "c");
ListIterator<String> iter = list.listIterator(list.size());
while (iter.hasPrevious()) System.out.println(iter.previous());
Результат: c b a
Здесь мы применили методы hasPrevious()
и previous()
интерфейса ListIterator
для обхода в обратном порядке.
Разработка индивидуального решения
Строим обратимый итератор
Для обхода коллекции в обратном порядке хорошим способом является создание специального класса. Вот пример декоратора, позволяющего выполнять обратное итерирование по List
, не модифицируя его:
public class Reversed<T> implements Iterable<T> {
private final List<T> original;
public Reversed(List<T> original) {
this.original = original;
}
public Iterator<T> iterator() {
final ListIterator<T> i = original.listIterator(original.size());
return new Iterator<T>() {
public boolean hasNext() {
return i.hasPrevious();
}
public T next() {
return i.previous();
}
public void remove() {
i.remove();
}
};
}
// Пример использования с циклом for-each:
// for (String element : new Reversed<>(list)) { ... }
}
Данный код позволяет осуществлять итерацию по любому List
с конца до начала.
Подход с использованием Google Guava
Если вам не против использования сторонних библиотек, Google Guava предложит весьма простой вариант:
List<String> reversed = Lists.reverse(list);
for(String element : reversed) {
System.out.println(element);
}
Хотя этот метод эффективен, прежде чем добавлять дополнительные зависимости, вам стоит учесть все возможные последствия.
Особенности работы с ArrayList
ArrayList обеспечивает быстрый доступ к элементам, что делает его совершенно подходящим для обратной итерации:
for (int i = list.size() – 1; i >= 0; i--) {
String element = list.get(i);
// Выполнение необходимых действий.
}
При использовании Collections.reverse()
следует помнить, что его вызов должен происходить до начала итерации:
Collections.reverse(list);
// Теперь можно обходить список стандартным for-each циклом
Однако не забывайте, что данный метод изменяет порядок элементов в исходном списке.
Визуализация
Предположим, у нас есть строка элементов:
🚗🚗🚗🚗🚗 // Исходный порядок.
Добавим нумерацию:
🚗5️⃣ 🚗4️⃣ 🚗3️⃣ 🚗2️⃣ 🚗1️⃣ // Элементы в обратном порядке.
В случае использования обратного foreach-цикла мы начинаем с последнего элемента:
// Счёт будет идти в обратном порядке
for (int i = list.size() – 1; i >= 0; i--) {
System.out.println(list.get(i)); // Выводим элементы, начиная с последнего
}
При каждой итерации определяется следующий элемент, пока список не останется пустым:
Конечная точка: 🏁🚗5️⃣ 🚗4️⃣ 🚗3️⃣ 🚗2️⃣ 🚗1️⃣ Стартовая точка
Таким образом, мы реализуем обратное выполнение цикла в Java.
Обработка проблемных ситуаций
Безопасное копирование
Когда вы хотите инвертировать список, не забывайте про особенности поверхностного копирования. Если вы работаете с изменяемыми объектами, используйте глубокое копирование:
List<String> clone = deepCopy(list);
Collections.reverse(clone);
Синхронизация для обеспечения безопасности
Если список изменяется в процессе итерации, применяйте синхронизацию или используйте конкурентные коллекции:
synchronized(list) {
for (String element : new Reversed<>(list)) {
// Прежде всего – синхронизация!
}
}
Удаление элементов во время итерации
С помощью ListIterator
можно удалять элементы в ходе обратного перебора, что недоступно при использовании цикла for-each:
while (iter.hasPrevious()) {
if (someCondition(iter.previous())) {
iter.remove(); // Мы удаляем элемент, если выполняется некое условие.
}
}
Будьте внимательны, чтобы не столкнуться с ConcurrentModificationException
.
Полезные материалы
- Iterable (Java Platform SE 8) – Официальная документация по
Iterable
. - Можно ли в Java использовать цикл for each в обратном порядке? – Stack Overflow – Обсуждение данной темы на Stack Overflow.
- Effective Java, 3rd edition – Книга о наилучших практиках программирования на Java, в том числе об использовании циклов.
- Java | Циклы | Codecademy – Учебные материалы по базовым конструкциям циклов в Java.
- Поиск · java reverse collection · GitHub – Примеры кода для реализации обратной итерации в Java на GitHub.