Паттерны использования
Относительная навигация
Валидация границ
Создание подсписков по позициям
Расширенные методы модификации
set(E e): Замена текущего элемента
Концептуальное назначение
Метод set(E e) позволяет заменить последний элемент, возвращенный вызовом next() или previous(). Это расширяет возможности итератора за пределы простого удаления, позволяя модифицировать содержимое списка во время итерации.
Семантика и поведение
Условия вызова: Может быть вызван только после успешного вызова next() или previous().
Исключения: Выбрасывает IllegalStateException, если не был вызван next() или previous(), или если после последнего вызова next()/previous() был вызван add() или remove().
Эффект: Заменяет элемент в списке без изменения размера коллекции или позиции итератора.
Внутренние механизмы реализации
Общий алгоритм
Реализация для ArrayList
Особенности:
Прямой доступ к массиву по индексу
Проверка границ массива
Сохранение позиции итератора
Реализация для LinkedList
Особенности:
Прямая модификация поля item узла
Не требует поиска узла
Высокая эффективность
Особенности производительности
Временная сложность:
ArrayList: O(1) — прямой доступ по индексу
LinkedList: O(1) — модификация существующего узла
Память: Может создавать новый объект, если заменяемый элемент становится недостижимым.
Потокобезопасность: Не является потокобезопасным.
#Java #для_новичков #beginner #ListIterator
Относительная навигация
public static <T> void processWithRelativeNavigation(List<T> list) {
ListIterator<T> iterator = list.listIterator();
while (iterator.hasNext()) {
int currentIndex = iterator.nextIndex();
T current = iterator.next();
// Обработка с учетом позиции
if (currentIndex % 2 == 0) {
// Четная позиция
processEvenPosition(current, currentIndex);
}
// Пропустить следующие 2 элемента, если возможно
if (iterator.hasNext()) {
iterator.next();
if (iterator.hasNext()) {
iterator.next();
}
}
}
}Валидация границ
public static <T> void safeBidirectionalProcessing(List<T> list) {
ListIterator<T> iterator = list.listIterator();
// Движение вперед с проверкой
while (iterator.hasNext()) {
int nextIdx = iterator.nextIndex();
if (nextIdx < list.size() / 2) {
// Только первая половина списка
T element = iterator.next();
processElement(element);
} else {
break;
}
}
// Движение назад
while (iterator.hasPrevious()) {
int prevIdx = iterator.previousIndex();
if (prevIdx >= 0) {
T element = iterator.previous();
reverseProcess(element);
}
}
}Создание подсписков по позициям
public static <T> List<T> extractSubList(List<T> list, int startIndex, int endIndex) {
List<T> result = new ArrayList<>();
ListIterator<T> iterator = list.listIterator(startIndex);
while (iterator.hasNext() && iterator.nextIndex() < endIndex) {
result.add(iterator.next());
}
return result;
}Расширенные методы модификации
set(E e): Замена текущего элемента
Концептуальное назначение
Метод set(E e) позволяет заменить последний элемент, возвращенный вызовом next() или previous(). Это расширяет возможности итератора за пределы простого удаления, позволяя модифицировать содержимое списка во время итерации.
Семантика и поведение
Условия вызова: Может быть вызван только после успешного вызова next() или previous().
Исключения: Выбрасывает IllegalStateException, если не был вызван next() или previous(), или если после последнего вызова next()/previous() был вызван add() или remove().
Эффект: Заменяет элемент в списке без изменения размера коллекции или позиции итератора.
Внутренние механизмы реализации
Общий алгоритм
public void set(E e) {
if (lastReturned == null) {
throw new IllegalStateException();
}
checkForComodification();
try {
// Замена элемента в списке
list.set(lastReturnedIndex, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}Реализация для ArrayList
public void set(E e) {
if (lastReturned < 0) {
throw new IllegalStateException();
}
checkForComodification();
try {
ArrayList.this.set(lastReturned, e);
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}Особенности:
Прямой доступ к массиву по индексу
Проверка границ массива
Сохранение позиции итератора
Реализация для LinkedList
public void set(E e) {
if (lastReturned == null) {
throw new IllegalStateException();
}
checkForComodification();
lastReturned.item = e;
}Особенности:
Прямая модификация поля item узла
Не требует поиска узла
Высокая эффективность
Особенности производительности
Временная сложность:
ArrayList: O(1) — прямой доступ по индексу
LinkedList: O(1) — модификация существующего узла
Память: Может создавать новый объект, если заменяемый элемент становится недостижимым.
Потокобезопасность: Не является потокобезопасным.
#Java #для_новичков #beginner #ListIterator
👍2
Паттерны использования
Модификация элементов на лету
Условная замена
Коррекция данных
add(E e): Вставка нового элемента
Концептуальное назначение
Метод add(E e) представляет собой наиболее мощную операцию ListIterator — он позволяет вставлять новые элементы в список непосредственно перед элементом, который будет возвращен следующим вызовом next(). Это уникальная возможность, недоступная в базовом Iterator.
Семантика и поведение
Позиция вставки: Элемент вставляется перед элементом, который будет возвращен next(), или в конец списка, если next() вернет NoSuchElementException.
Влияние на итератор: После вставки последующий вызов next() вернет новый элемент, а previous() вернет только что вставленный элемент.
Состояние: Сбрасывает состояние lastReturned, поэтому последующий вызов remove() или set() выбросит исключение до следующего вызова next() или previous().
Внутренние механизмы реализации
Общий алгоритм
Реализация для ArrayList
Особенности:
Вызов ArrayList.add(index, element) со сдвигом элементов
Корректировка курсора и счетчиков
Обработка возможного расширения массива
Реализация для LinkedList
Особенности:
Эффективная вставка за O(1) после нахождения позиции
Манипуляции со ссылками между узлами
Автоматическая обработка граничных условий
Особенности производительности
Временная сложность:
ArrayList: O(n) — требуется сдвиг элементов
LinkedList: O(1) — вставка в найденную позицию
Память: Создает новый объект узла (LinkedList) или может вызвать расширение массива (ArrayList).
Потокобезопасность: Не является потокобезопасным.
#Java #для_новичков #beginner #ListIterator
Модификация элементов на лету
public static void transformStrings(List<String> strings) {
ListIterator<String> iterator = strings.listIterator();
while (iterator.hasNext()) {
String original = iterator.next();
String transformed = original.toUpperCase();
iterator.set(transformed);
}
}Условная замена
public static void replaceIf(List<Integer> numbers, Predicate<Integer> condition, Integer replacement) {
ListIterator<Integer> iterator = numbers.listIterator();
while (iterator.hasNext()) {
Integer current = iterator.next();
if (condition.test(current)) {
iterator.set(replacement);
}
}
}Коррекция данных
public static void correctDataSequence(List<DataPoint> data) {
if (data.isEmpty()) return;
ListIterator<DataPoint> iterator = data.listIterator();
DataPoint previous = iterator.next();
while (iterator.hasNext()) {
DataPoint current = iterator.next();
// Коррекция аномальных значений
if (isAnomaly(current, previous)) {
DataPoint corrected = interpolate(previous, current);
iterator.set(corrected);
}
previous = current;
}
}add(E e): Вставка нового элемента
Концептуальное назначение
Метод add(E e) представляет собой наиболее мощную операцию ListIterator — он позволяет вставлять новые элементы в список непосредственно перед элементом, который будет возвращен следующим вызовом next(). Это уникальная возможность, недоступная в базовом Iterator.
Семантика и поведение
Позиция вставки: Элемент вставляется перед элементом, который будет возвращен next(), или в конец списка, если next() вернет NoSuchElementException.
Влияние на итератор: После вставки последующий вызов next() вернет новый элемент, а previous() вернет только что вставленный элемент.
Состояние: Сбрасывает состояние lastReturned, поэтому последующий вызов remove() или set() выбросит исключение до следующего вызова next() или previous().
Внутренние механизмы реализации
Общий алгоритм
public void add(E e) {
checkForComodification();
try {
int i = cursor;
// Вставка в список
list.add(i, e);
// Корректировка состояния итератора
cursor = i + 1;
lastReturned = null;
nextIndex++;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}Реализация для ArrayList
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastReturned = null;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}Особенности:
Вызов ArrayList.add(index, element) со сдвигом элементов
Корректировка курсора и счетчиков
Обработка возможного расширения массива
Реализация для LinkedList
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null) {
// Вставка в конец
linkLast(e);
} else {
// Вставка перед next
linkBefore(e, next);
}
nextIndex++;
expectedModCount++;
}Особенности:
Эффективная вставка за O(1) после нахождения позиции
Манипуляции со ссылками между узлами
Автоматическая обработка граничных условий
Особенности производительности
Временная сложность:
ArrayList: O(n) — требуется сдвиг элементов
LinkedList: O(1) — вставка в найденную позицию
Память: Создает новый объект узла (LinkedList) или может вызвать расширение массива (ArrayList).
Потокобезопасность: Не является потокобезопасным.
#Java #для_новичков #beginner #ListIterator
👍2
Паттерны использования
Динамическое пополнение списка
Интерполяция пропущенных значений
Построение упорядоченного списка
Интеграция всех методов: Сложные сценарии использования
Полный цикл двунаправленной обработки
Динамическое пополнение списка
public static void expandListWithPrimes(List<Integer> numbers) {
ListIterator<Integer> iterator = numbers.listIterator();
while (iterator.hasNext()) {
Integer current = iterator.next();
if (isPrime(current)) {
// Вставляем квадрат простого числа перед ним
iterator.previous(); // Возвращаемся к простому числу
iterator.add(current * current);
iterator.next(); // Продолжаем с исходного элемента
}
}
}Интерполяция пропущенных значений
public static void interpolateMissing(List<Double> values) {
if (values.size() < 2) return;
ListIterator<Double> iterator = values.listIterator();
Double prev = iterator.next();
while (iterator.hasNext()) {
Double current = iterator.next();
if (current == null && prev != null) {
// Нашли null после non-null значения
// Возвращаемся к null и заменяем его интерполированным значением
iterator.previous(); // Переходим к null
iterator.set((prev + getNextNonNull(iterator)) / 2);
iterator.next(); // Продолжаем
}
prev = current;
}
}Построение упорядоченного списка
public static <T extends Comparable<T>> void insertSorted(List<T> sortedList, T newElement) {
ListIterator<T> iterator = sortedList.listIterator();
while (iterator.hasNext()) {
if (newElement.compareTo(iterator.next()) < 0) {
// Нашли позицию для вставки
iterator.previous(); // Возвращаемся к элементу, который больше нового
iterator.add(newElement);
return;
}
}
// Новый элемент больше всех существующих
iterator.add(newElement);
}Интеграция всех методов: Сложные сценарии использования
Полный цикл двунаправленной обработки
public class AdvancedListProcessing {
public static <T> void bidirectionalTransform(List<T> list,
Function<T, T> forwardTransform,
Function<T, T> backwardTransform) {
ListIterator<T> iterator = list.listIterator();
// Фаза 1: Прямой обход с трансформацией
while (iterator.hasNext()) {
T original = iterator.next();
T transformed = forwardTransform.apply(original);
iterator.set(transformed);
}
// Фаза 2: Обратный обход с дополнительной трансформацией
while (iterator.hasPrevious()) {
T current = iterator.previous();
T doublyTransformed = backwardTransform.apply(current);
// Условная вставка нового элемента
if (shouldInsertAfter(current)) {
iterator.next(); // Переходим к следующей позиции для вставки
iterator.add(generateNewElement(current));
iterator.previous(); // Возвращаемся к текущему элементу
}
iterator.set(doublyTransformed);
}
}
public static <T> List<T> mergeAdjacentDuplicates(List<T> list) {
if (list.size() < 2) {
return new ArrayList<>(list);
}
ListIterator<T> iterator = list.listIterator();
List<T> result = new ArrayList<>();
T current = iterator.next();
result.add(current);
while (iterator.hasNext()) {
T next = iterator.next();
if (!current.equals(next)) {
// Разные элементы - добавляем в результат
result.add(next);
current = next;
} else {
// Дубликат - пропускаем
// При необходимости можно выполнить merge операцию
mergeLastTwo(result);
}
}
return result;
}
public static <T> void processWithLookaheadAndLookbehind(List<T> list,👍2
BiFunction<T, T, T> lookaheadProcessor,
BiFunction<T, T, T> lookbehindProcessor) {
if (list.size() < 2) return;
ListIterator<T> iterator = list.listIterator();
// Обработка с lookahead
while (iterator.hasNext()) {
int currentIndex = iterator.nextIndex();
T current = iterator.next();
if (iterator.hasNext()) {
// Есть следующий элемент для lookahead
T lookahead = iterator.next();
T processed = lookaheadProcessor.apply(current, lookahead);
// Возвращаемся и заменяем текущий элемент
iterator.previous(); // К lookahead
iterator.previous(); // К current
iterator.set(processed);
iterator.next(); // К lookahead
iterator.next(); // К следующему элементу для продолжения
}
}
// Обработка с lookbehind
while (iterator.hasPrevious()) {
T current = iterator.previous();
if (iterator.hasPrevious()) {
T lookbehind = iterator.previous();
T processed = lookbehindProcessor.apply(current, lookbehind);
// Возвращаемся и заменяем
iterator.next(); // К lookbehind
iterator.next(); // К current
iterator.set(processed);
iterator.previous(); // К lookbehind для продолжения
}
}
}
}
Управление состоянием и переходы
Диаграмма состояний ListIterator
Состояния:
1. Инициализация: lastReturned = null, cursor = 0
2. После next(): lastReturned = элемент, cursor = nextIndex
3. После previous(): lastReturned = элемент, cursor = previousIndex + 1
4. После remove(): lastReturned = null
5. После set(): lastReturned остается установленным
6. После add(): lastReturned = null, cursor увеличивается на 1
Допустимые переходы:
- next() → remove() ✓, set() ✓, add() ✓
- previous() → remove() ✓, set() ✓, add() ✓
- remove() → next() ✓, previous() ✓, add() ✗, set() ✗, remove() ✗
- set() → next() ✓, previous() ✓, remove() ✗, add() ✗
- add() → next() ✓, previous() ✓, remove() ✗, set() ✗
Валидация последовательности операций
public class ListIteratorValidator {
public static <T> boolean validateOperationSequence(ListIterator<T> iterator,
List<String> operations) {
boolean canRemoveOrSet = false;
for (String op : operations) {
switch (op) {
case "next":
if (!iterator.hasNext()) return false;
iterator.next();
canRemoveOrSet = true;
break;
case "previous":
if (!iterator.hasPrevious()) return false;
iterator.previous();
canRemoveOrSet = true;
break;
case "remove":
if (!canRemoveOrSet) return false;
iterator.remove();
canRemoveOrSet = false;
break;
case "set":
if (!canRemoveOrSet) return false;
// Необходим элемент для замены
iterator.set(null); // Упрощенная проверка
canRemoveOrSet = false;
break;
case "add":
iterator.add(null); // Всегда допустимо
canRemoveOrSet = false;
break;
default:
return false;
}
}
return true;
}
}#Java #для_новичков #beginner #ListIterator
👍2
Оптимизированные паттерны использования
Эффективное использование для ArrayList
Эффективное использование для LinkedList
#Java #для_новичков #beginner #ListIterator
Эффективное использование для ArrayList
public class ArrayListOptimizations {
// Избегайте частых add() и remove() в середине списка
public static void efficientArrayListProcessing(List<String> list) {
// Вместо множественных add() через ListIterator
// Собирайте изменения и применяйте их пакетно
List<String> toAdd = new ArrayList<>();
ListIterator<String> iterator = list.listIterator();
while (iterator.hasNext()) {
String current = iterator.next();
if (shouldDuplicate(current)) {
toAdd.add(current + "_copy");
}
}
// Пакетное добавление в конец
list.addAll(toAdd);
}
// Используйте set() вместо remove() + add() для замены
public static void replaceEfficiently(List<Integer> numbers) {
ListIterator<Integer> iterator = numbers.listIterator();
while (iterator.hasNext()) {
Integer current = iterator.next();
if (current % 2 == 0) {
iterator.set(current * 2); // Эффективнее, чем remove() + add()
}
}
}
}Эффективное использование для LinkedList
public class LinkedListOptimizations {
// LinkedList идеально подходит для частых вставок/удалений через ListIterator
public static void efficientLinkedListProcessing(LinkedList<String> list) {
ListIterator<String> iterator = list.listIterator();
// Частые вставки эффективны
while (iterator.hasNext()) {
String current = iterator.next();
if (requiresPrefix(current)) {
iterator.add("prefix_" + current);
}
}
// Частые удаления также эффективны
iterator = list.listIterator();
while (iterator.hasNext()) {
if (shouldRemove(iterator.next())) {
iterator.remove();
}
}
}
// Использование previous() для навигации назад
public static void findAndProcessFromEnd(LinkedList<String> list, String target) {
ListIterator<String> iterator = list.listIterator(list.size());
while (iterator.hasPrevious()) {
String current = iterator.previous();
if (current.equals(target)) {
// Нашли - обрабатываем и можем идти в обе стороны
processFound(current);
// Можем продолжить в любом направлении
if (iterator.hasPrevious()) {
processPrevious(iterator.previous());
}
if (iterator.hasNext()) {
processNext(iterator.next());
}
break;
}
}
}
}#Java #для_новичков #beginner #ListIterator
👍2
Best Practices
1. Выбор начальной позиции
2. Минимизация переходов между next() и previous()
3. Использование nextIndex()/previousIndex() для логики, зависящей от позиции
4. Безопасность в многопоточных сценариях
#Java #для_новичков #beginner #ListIterator
1. Выбор начальной позиции
// Начинайте с нужной позиции, а не всегда с начала
ListIterator<T> iterator = list.listIterator(startPosition);
// Для обработки с конца
ListIterator<T> reverseIterator = list.listIterator(list.size());
2. Минимизация переходов между next() и previous()
// Неэффективно:
while (iterator.hasNext()) {
T current = iterator.next();
if (condition(current)) {
iterator.previous(); // Дорогой переход
iterator.add(newElement);
iterator.next(); // Еще один переход
iterator.next(); // Пропускаем добавленный элемент
}
}
// Более эффективно:
while (iterator.hasNext()) {
T current = iterator.next();
if (condition(current)) {
iterator.add(newElement);
// current остался тем же, newElement теперь перед ним
}
}
3. Использование nextIndex()/previousIndex() для логики, зависящей от позиции
ListIterator<T> iterator = list.listIterator();
while (iterator.hasNext()) {
int currentIndex = iterator.nextIndex();
T element = iterator.next();
if (currentIndex % 2 == 0) {
// Обработка четных позиций
processEven(element, currentIndex);
}
}
4. Безопасность в многопоточных сценариях
// Всегда синхронизируйте доступ к ListIterator
synchronized(list) {
ListIterator<T> iterator = list.listIterator();
while (iterator.hasNext()) {
// Обработка
}
}
// Или используйте потокобезопасные альтернативы
List<T> syncList = Collections.synchronizedList(new ArrayList<>());
// Но даже synchronizedList требует внешней синхронизации для итерации
#Java #для_новичков #beginner #ListIterator
👍2
Что выведет код?
#Tasks
import java.util.*;
public class Task121225 {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
ListIterator<String> it = list.listIterator();
System.out.print(it.next() + " ");
System.out.print(it.next() + " ");
it.add("X");
System.out.print(it.previous() + " ");
System.out.print(it.next() + " ");
System.out.print(it.previous() + " ");
it.remove();
System.out.println(list);
}
}
#Tasks
👍1
Варианты ответа:
Anonymous Quiz
38%
A B X C X [A, B, C, D]
38%
A B X X X [A, B, X, C, D]
25%
A B X X [A, B, C, D]
0%
A B X X [A, B, X, C, D]
👍1
Вопрос с собеседований
Как работает ReentrantReadWriteLock?🤓
Ответ:
Он разделяет блокировки на read и write.
Несколько читателей могут работать одновременно, но запись блокируется полностью. Это повышает производительность, если чтений больше, чем записей.
Однако write-блокировка может вызывать «голодание» читателей.
#собеседование
Как работает ReentrantReadWriteLock?
Ответ:
Несколько читателей могут работать одновременно, но запись блокируется полностью. Это повышает производительность, если чтений больше, чем записей.
Однако write-блокировка может вызывать «голодание» читателей.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История IT-технологий сегодня — 13 декабря
ℹ️ Кто родился в этот день
Дже́йми Ве́рнер Зави́нски (англ. Jamie Werner Zawinski, известный также как jwz; род. 3 ноября 1968, Питтсбург, Пенсильвания) — программист, один из ключевых разработчиков Netscape и Mozilla; активно повлиял на развитие ранних браузеров и веб-экосистемы.
🌐 Знаковые события
1967 — в США состоялся успешный запуск космического аппарата «Пионер-8».
#Biography #Birth_Date #Events #13Декабря
Дже́йми Ве́рнер Зави́нски (англ. Jamie Werner Zawinski, известный также как jwz; род. 3 ноября 1968, Питтсбург, Пенсильвания) — программист, один из ключевых разработчиков Netscape и Mozilla; активно повлиял на развитие ранних браузеров и веб-экосистемы.
1967 — в США состоялся успешный запуск космического аппарата «Пионер-8».
#Biography #Birth_Date #Events #13Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
С 06.12 по 12.12
Предыдущий пост(с С 29.11 по 05.12)
Воскресный мотивационный пост:
Не было мотивации
Запись встреч/видео:
не было
Обучающие статьи:
Java:
Коллекции в Java
Глава 2. List — списки в Java
Практика
Глава 6. Итераторы
Интерфейс Iterator — фундаментальный механизм обхода коллекций
Интерфейс ListIterator — двунаправленный обход и расширенные возможности
Spring Cloud Gateway
Конфигурация маршрутов в Spring Cloud Gateway
Predicates (условия маршрутизации)
Полезные статьи и видео:
ПОДКЛЮЧЕНИЕ GPT GO на ГОД!
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с С 29.11 по 05.12)
Воскресный мотивационный пост:
Не было мотивации
Запись встреч/видео:
не было
Обучающие статьи:
Java:
Коллекции в Java
Глава 2. List — списки в Java
Практика
Глава 6. Итераторы
Интерфейс Iterator — фундаментальный механизм обхода коллекций
Интерфейс ListIterator — двунаправленный обход и расширенные возможности
Spring Cloud Gateway
Конфигурация маршрутов в Spring Cloud Gateway
Predicates (условия маршрутизации)
Полезные статьи и видео:
ПОДКЛЮЧЕНИЕ GPT GO на ГОД!
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍1
Ну что встречаемся завтра?
Можно что-то новое рассмотреть, если желание есть😜
Предлагайте👍
Можно что-то новое рассмотреть, если желание есть
Предлагайте
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1