Deque.pollLast: примеры (JAVA)
Deque.pollLast: EОбщее описание метода pollLast()
Метод pollLast() интерфейса java.util.Deque извлекает и удаляет последний элемент коллекции. Если коллекция пуста, возвращается null, вместо генерации исключения. Подход применим при необходимости безопасного получения элемента с конца без обработки исключений.
Сигнатуры и варианты:
E pollLast()- из java.util.Deque. Не принимает аргументов. Возвращает элемент типаEилиnull, если deque пуст.E pollLast(long timeout, java.util.concurrent.TimeUnit unit) throws InterruptedException- из java.util.concurrent.BlockingDeque. Блокирует поток до появления элемента или до истечения таймаута; при истечении времени возвращаетnull. Может выброситьInterruptedException.
Поведение и особенности:
- Метод удаляет элемент из структуры. Для получения без удаления используется
peekLast(). - Возвращаемое
nullодновременно означает либо пустую коллекцию, либо (в редких реализациях, допускающих null) реальное значениеnull. Большинство реализаций стандартной библиотеки Java не допускаютnullкак элемент и используютnullисключительно для обозначения пустоты. - Альтернативы:
removeLast()(генерируетNoSuchElementExceptionпри пустой коллекции),pollFirst(),peekLast(), блокирующий вариант в BlockingDeque. - Поведение в многопоточной среде зависит от конкретной реализации (например,
ConcurrentLinkedDeque,LinkedBlockingDequeи другие имеют разную гарантию согласованности и блокировки).
Примеры базового использования
Примеры показывают разные реализации и варианты ответа метода.
1) ArrayDeque: удаление последнего элемента
import java.util.ArrayDeque;
import java.util.Deque;
Deque<String> dq = new ArrayDeque<>();
dq.add("a");
dq.add("b");
String last = dq.pollLast();
System.out.println(last);
System.out.println(dq);
b [a]
2) Поведение при пустой коллекции
Deque<Integer> empty = new java.util.ArrayDeque<>();
Integer v = empty.pollLast();
System.out.println(v);
null
3) Сравнение с removeLast()
Deque<Integer> d = new java.util.ArrayDeque<>();
System.out.println(d.pollLast());
try {
d.removeLast();
} catch (Exception e) {
System.out.println(e.getClass().getSimpleName());
}
null NoSuchElementException
4) Блокирующий вариант с таймаутом в LinkedBlockingDeque
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
LinkedBlockingDeque<String> bq = new LinkedBlockingDeque<>();
String r = bq.pollLast(500, TimeUnit.MILLISECONDS); // ждет 500 мс
System.out.println(r);
null
Похожие методы в Java
- peekLast() - возвращает последний элемент без удаления; при пустой коллекции возвращает
null. - removeLast() - удаляет и возвращает последний элемент, но при пустой коллекции генерирует
NoSuchElementException. Предпочтительнее при подразумеваемой гарантии непустой коллекции. - pollFirst() - аналогично
pollLast(), но с начала коллекции. - offerLast(E) / addLast(E) - добавление в конец; в блокирующих реализациях есть временные варианты.
- BlockingDeque.pollLast(long, TimeUnit) - блокирующий вариант с таймаутом; подходит для потребителей в многопоточном обмене.
Выбор зависит от требований: если нежелательна обработка исключений - использовать pollLast(); если пустота считается ошибкой - removeLast(). Для неблокирующего многопоточного доступа выбирается подходящая concurrent-реализация.
Аналоги в других языках
Краткие сравнения и примеры поведения.
- JavaScript: стандартные массивы используют
pop(), который удаляет и возвращает последний элемент, но при пустом массиве возвращаетundefined.
const a = [];
console.log(a.pop());
undefined
- Python:
collections.deque.pop()удаляет последний элемент и при пустой коллекции возбуждаетIndexError. Для безопасного доступа используется проверка на пустоту или обработка исключения.
from collections import deque
q = deque()
try:
print(q.pop())
except Exception as e:
print(type(e).__name__)
IndexError
- PHP:
array_pop()для массивов возвращаетnullпри пустом массиве; классSplDoublyLinkedListимеет методыpop()иshift().
$a = [];
var_dump(array_pop($a));
NULL
- C#: нет встроенного Deque в BCL; для похожего поведения используется
LinkedList<T>сLastиRemoveLast(). При пустой коллекции доступ кLastдастnullу ссылочных типов либо требуется проверка.
var ll = new System.Collections.Generic.LinkedList<int>();
// нужно проверять ll.Last перед удалением
(нет вывода)
- Go: пакет
container/listпредоставляет двусвязный список; методBack()возвращает элемент илиnil, аRemoveудаляет его.
import (
"container/list"
"fmt"
)
l := list.New()
if e := l.Back(); e != nil {
val := e.Value
l.Remove(e)
fmt.Println(val)
} else {
fmt.Println(nil)
}
<nil>
- Kotlin: при использовании java.util.Deque вызываются те же методы; в стандартной Kotlin коллекции есть методы вроде
removeLastOrNull()(в некоторых версиях) - возвращаютnullпри пустой коллекции.
Ключевое отличие от Java: в некоторых языках (JavaScript, PHP, Go) безопасное значение при пустоте - undefined / null, тогда как Python предпочитает бросать исключение. Это влияет на стиль обработки: проверка на пустоту или ловля исключения.
Типичные ошибки и подводные камни
- Ошибка: ожидание исключения при пустой коллекции. Многие используют
pollLast(), ожидая исключение, но метод возвращаетnull. Пример:
Deque<String> d = new ArrayDeque<>();
String s = d.pollLast();
if (s == null) {
System.out.println("пусто");
}
пусто
- Ошибка: добавление
nullв реализацию, не допускающую null. Многие реализации, включаяArrayDeque, не допускаютnullи при попытке добавления выбросятNullPointerException.
Deque<String> dq = new ArrayDeque<>();
try {
dq.add(null);
} catch (Exception e) {
System.out.println(e.getClass().getSimpleName());
}
NullPointerException
- Ошибка: неверная работа в многопоточной среде при использовании небезопасных реализаций. Для параллельных сценариев требуется выбрать concurrent-реализацию или блокирующую очередь.
- Ошибка: игнорирование InterruptedException у
BlockingDeque.pollLast(timeout, unit). Требуется обработка прерываний.
Изменения и совместимость
Сам интерфейс Deque и метод pollLast() существуют в Java достаточно давно и не претерпевали значительных изменений в сигнатуре в последних релизах. Блокирующие варианты находятся в BlockingDeque (java.util.concurrent) и также стабилизированы.
В новых версиях платформы появлялись и появляются улучшенные реализации и оптимизации (например, улучшения производительности ArrayDeque и concurrent-коллекций), но семантика pollLast() сохраняется: извлечение и удаление элемента с конца с возвратом null для пустой коллекции.
Расширенные примеры и нетривиальные сценарии
1) Потребитель-производитель с LinkedBlockingDeque и таймаутом
import java.util.concurrent.*;
LinkedBlockingDeque<String> queue = new LinkedBlockingDeque<>();
ExecutorService ex = Executors.newFixedThreadPool(2);
ex.submit(() -> {
try {
Thread.sleep(200);
queue.putLast("job1");
} catch (InterruptedException ignored) {}
});
ex.submit(() -> {
try {
String item = queue.pollLast(1, TimeUnit.SECONDS);
System.out.println(item);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
});
ex.shutdown();
ex.awaitTermination(2, TimeUnit.SECONDS);
job1
Комментарий: блокирующий вариант удобен для ожидания появления элемента с ограничением по времени и корректной обработкой прерываний.
2) Реализация алгоритма «скользящее максимальное окно» с помощью Deque (удаление с конца при меньших значениях)
import java.util.*;
int[] a = {1,3,1,2,0,5};
int k = 3;
Deque<Integer> dq = new ArrayDeque<>(); // хранит индексы
List<Integer> res = new ArrayList<>();
for (int i = 0; i < a.length; i++) {
while (!dq.isEmpty() && a[dq.peekLast()] <= a[i]) dq.pollLast();
dq.addLast(i);
if (dq.peekFirst() <= i - k) dq.pollFirst();
if (i >= k - 1) res.add(a[dq.peekFirst()]);
}
System.out.println(res);
[3, 3, 2, 5]
Комментарий: здесь pollLast() используется для удаления индексов с конца, чьи значения не полезны для будущих максимумов.
3) Безопасное извлечение из ConcurrentLinkedDeque в многопоточности
import java.util.concurrent.ConcurrentLinkedDeque;
ConcurrentLinkedDeque<String> cld = new ConcurrentLinkedDeque<>();
cld.add("x");
cld.add("y");
String e;
while ((e = cld.pollLast()) != null) {
System.out.println(e);
}
System.out.println(cld.size());
y x 0
Комментарий: в lock-free структурах pollLast() обеспечивает безопасное неблокирующее извлечение несколькими потоками одновременно.
4) Использование pollLast в реализации кэша LRU (удаление наименее недавно используемого)
// Упрощенный пример: двусвязный deque хранит ключи, при переполнении удаляется последний
Deque<String> order = new ArrayDeque<>();
Map<String,String> map = new HashMap<>();
int capacity = 2;
void put(String k, String v) {
if (map.containsKey(k)) {
order.remove(k);
} else if (map.size() >= capacity) {
String lru = order.pollLast();
map.remove(lru);
}
order.addFirst(k);
map.put(k, v);
}
// демонстрация
put("a","1");
put("b","2");
put("c","3");
System.out.println(map.keySet());
[c, b]
Комментарий: pollLast() позволяет извлечь и удалить наименее недавно использованный ключ.