Collections.asLifoQueue: примеры (JAVA)
Collections.asLifoQueue(Deque deque): Queue Описание и сигнатура
Метод Collections.asLifoQueue предоставляет адаптер, превращающий любой объект, реализующий интерфейс Deque<E>, в представление типа Queue<E> с поведением LIFO (последним пришёл - первым вышел). Возвращаемый объект является видом (view) на переданный Deque, то есть операции над адаптером влияют на исходную структуру и наоборот.
Сигнатура:
public static <T> Queue<T> asLifoQueue(Deque<T> deque)
Аргументы:
deque- обязательный параметр типаDeque<T>. Нельзя передаватьnull. Поддержкаnull-элементов зависит от конкретной реализацииDeque.
Возвращаемое значение:
- Возвращается объект
Queue<T>, который использует методыdequeдля реализации операций очереди в LIFO-манере: добавление выполняется через добавление в вершину (аналогичноaddFirst), удаление и просмотр элемента - через доступ к вершине (removeFirst/peekFirstи т.д.). - Возвращаемый объект не копирует содержимое
deque, это представление поверх него.
Поведение основных методов (соответствие вызовов):
add(e)/offer(e)→ вставка в начало: аналогdeque.addFirst(e)/deque.offerFirst(e).remove()/poll()→ удаление из начала: аналогdeque.removeFirst()/deque.pollFirst().element()/peek()→ просмотр первого элемента: аналогdeque.getFirst()/deque.peekFirst().- Методы
size(),isEmpty(),contains(Object)и т.д. делегируются напрямую наdeque.
Особенности и ограничения:
- Если
dequeравенnull, будет выброшеноNullPointerException. - Возвращаемая очередь наследует ограничения и семантику исходного
Deque: поддержкаnull, ограничения размера, потокобезопасность зависят от конкретной реализации. - Если исходный
Dequeне поддерживает операцию (например, является неизменяемым), соответствующие вызовы адаптера породятUnsupportedOperationException.
Короткие примеры использования
Пример 1: базовые операции с ArrayDeque
import java.util.*;
public class Example1 {
public static void main(String[] args) {
Deque<String> deque = new ArrayDeque<>();
Queue<String> lifo = Collections.asLifoQueue(deque);
lifo.add("A");
lifo.add("B");
lifo.add("C");
System.out.println(lifo.poll()); // извлекает C
System.out.println(lifo.peek()); // показывает B
System.out.println(lifo.remove()); // извлекает B
System.out.println(lifo.poll()); // извлекает A
System.out.println(lifo.poll()); // null
}
}
C B B A null
Пример 2: адаптер над LinkedList с проверкой null
import java.util.*;
public class Example2 {
public static void main(String[] args) {
Deque<Integer> deque = new LinkedList<>();
Queue<Integer> lifo = Collections.asLifoQueue(deque);
lifo.offer(1);
lifo.offer(2);
lifo.offer(3);
// LinkedList допускает null, но адаптер использует методы deque
deque.addFirst(null);
System.out.println(lifo.poll()); // null (вершина)
System.out.println(lifo.poll()); // 3
}
}
null 3
Пример 3: передача адаптера туда, где требуется Queue
import java.util.*;
public class Example3 {
static void processQueue(Queue<String> q) {
q.add("X");
System.out.println(q.poll());
}
public static void main(String[] args) {
Deque<String> deque = new ArrayDeque<>();
Queue<String> lifo = Collections.asLifoQueue(deque);
processQueue(lifo); // работает как LIFO
}
}
X
Аналоги в Java и их свойства
- Deque напрямую
- ArrayDeque и LinkedList
- Stack (устаревший)
- BlockingDeque
Интерфейс Deque поддерживает методы push/pop и addFirst/removeFirst. При работе со стековой семантикой предпочтительнее использовать Deque напрямую, так как он предоставляет явные операции стека.
Конкретные реализации ArrayDeque и LinkedList часто используются как стек. ArrayDeque обычно быстрее и более предпочтителен для большинства задач, если не требуется доп. поведение списка.
Класс Stack<E> унаследован от Vector и считается устаревшим по сравнению с реализациями на основе Deque. Предпочтение обычно отдают Deque.
Если требуется блокирующая LIFO-очередь, можно использовать LinkedBlockingDeque и его методы putFirst/takeFirst. Обёртка Collections.asLifoQueue вернёт неполноценное представление, которое не содержит блокирующих методов, поэтому в многопоточной блокирующей среде лучше работать с BlockingDeque напрямую.
Эквиваленты в других языках и отличия
- Python
Модуль collections.deque используется как стек: append / pop. Отличие: API прямо поддерживает LIFO; вид-адаптера не нужен.
from collections import deque
d = deque()
d.append('A')
d.append('B')
print(d.pop())
print(d.pop())
B A
Массивы используются как стек через push/pop. Нет отдельного адаптера.
const a = [];
a.push('A');
a.push('B');
console.log(a.pop());
console.log(a.pop());
B A
Класс Stack<T> предоставляет стековую семантику. Также есть ConcurrentStack<T>.
using System;
using System.Collections.Generic;
class P{ static void Main(){
var s = new Stack<string>();
s.Push("A"); s.Push("B");
Console.WriteLine(s.Pop());
Console.WriteLine(s.Pop());
}}
B A
Можно использовать массив с array_push/array_pop или SplStack. Отличие: нет адаптера из двойной очереди.
$s = [];
array_push($s, 'A');
array_push($s, 'B');
echo array_pop($s) . PHP_EOL;
echo array_pop($s) . PHP_EOL;
B A
В стандартной библиотеке стека нет, используют срезы или container/list - push/pop реализуются вручную. Отличие: отсутствие встроенного адаптера.
package main
import "fmt"
func main(){
s := []string{}
s = append(s, "A")
s = append(s, "B")
fmt.Println(s[len(s)-1])
s = s[:len(s)-1]
}
B
При запуске на JVM используются те же коллекции, что и в Java. Kotlin-коллекция ArrayDeque также доступна и предоставляет методы для работы со стеком. Отличие: Kotlin предлагает более выразительный синтаксис и расширения.
Типичные ошибки и их причины
- NullPointerException при передаче null
Если вызвать Collections.asLifoQueue(null), будет выброшен NullPointerException.
Queue<String> q = Collections.asLifoQueue(null);
Exception in thread "main" java.lang.NullPointerException at java.util.Objects.requireNonNull(Objects.java:...) // примерный стек
Если передан неизменяемый или ограниченный по операциям Deque, попытка добавления через адаптер приведёт к UnsupportedOperationException.
Deque<String> d = Collections.unmodifiableCollection(new ArrayDeque<>());
Queue<String> q = Collections.asLifoQueue((Deque<String>) d);
q.add("X");
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableCollection.add(Collections.java:...)
Итератор адаптера использует порядок итерации Deque. Если элементы добавлялись в начало, итератор вернёт их от вершины к низу. Непонимание этого может привести к неожиданным результатам при обходе.
Адаптер не добавляет синхронизации. Если требуется потокобезопасность, следует использовать потокобезопасную реализацию Deque (например, ConcurrentLinkedDeque) или блокирующие структуры и работать с ними напрямую.
Изменения в поведении и совместимость
API Collections.asLifoQueue представляет простую адаптацию и в целом не претерпевал существенных изменений. Поведение стабильно: метод возвращает view над переданным Deque и делегирует операции ему. Изменения в релизах Java касались в основном общей библиотеки коллекций и появлению новых реализаций Deque и Concurrent-реализаций, которые можно использовать в сочетании с адаптером.
Замечания по совместимости:
- Поведение зависит от реализации
Deque, поэтому при обновлении JDK могут появиться новые реализации с лучшей производительностью, но семантика адаптера останется прежней.
Расширенные и редкие сценарии использования
1) Потокобезопасный LIFO через ConcurrentLinkedDeque
import java.util.*;
import java.util.concurrent.*;
public class Adv1 {
public static void main(String[] args) throws InterruptedException {
Deque<String> deque = new ConcurrentLinkedDeque<>();
Queue<String> lifo = Collections.asLifoQueue(deque);
Runnable producer = () -> {
for (int i = 0; i < 3; i++) lifo.add(Thread.currentThread().getName() + "-" + i);
};
Thread t1 = new Thread(producer, "P1");
Thread t2 = new Thread(producer, "P2");
t1.start(); t2.start();
t1.join(); t2.join();
String e;
while ((e = lifo.poll()) != null) System.out.println(e);
}
}
P2-2 P2-1 P2-0 P1-2 P1-1 P1-0
Вывод может варьироваться, но порядок извлечения для каждого потока остаётся LIFO относительно его вставок в деку.
2) Использование с BlockingDeque для получения LIFO-очереди с блокировкой (примечание)
Если передать LinkedBlockingDeque в asLifoQueue, получится Queue-view без блокирующих методов. Для блокирующей LIFO-логики требуется работать напрямую с BlockingDeque (например, putFirst/takeFirst).
import java.util.concurrent.*;
public class Adv2 {
public static void main(String[] args) throws InterruptedException {
LinkedBlockingDeque<String> deque = new LinkedBlockingDeque<>();
// Лучше использовать методы BlockingDeque напрямую
deque.putFirst("A");
System.out.println(deque.takeFirst());
}
}
A
3) Обёртка адаптера для передачи в API, ожидающее Queue
Некоторые сторонние библиотеки принимают Queue. В таком случае можно передать LIFO-адаптер, чтобы обеспечить стековую семантику без изменения сигнатуры API.
// Имеется метод библиотеки: void handle(Queue<String> q)
// Можно передать Collections.asLifoQueue(deque) и внутри handle
// будут использоваться методы очереди, но фактически с LIFO-порядком.
(Зависит от конкретного API, явный вывод отсутствует)
4) Комбинация с synchronized коллекциями
Если требуется простая синхронизация, можно синхронизировать исходный дек: вызов Collections.synchronizedCollection или синхронизировать блоки вокруг обращений. Однако для высоконагруженных сценариев предпочтительнее использовать concurrent-реализации.
Deque<String> deque = new ArrayDeque<>();
Queue<String> lifo = Collections.asLifoQueue(deque);
synchronized(deque) {
lifo.add("X");
}
(Нет прямого вывода, демонстрация синхронизации)
5) Сериализация и совместимость представления
Адаптер сам по себе не сериализируем, даже если исходный Deque реализует Serializable. В случаях, когда требуется сериализация, рекомендуется сериализовать сам Deque или создать копию содержимого в сериализуемой структуре.
// Рекомендуется сериализовать сам deque, а не адаптер
(Совет по проектированию, вывода нет)
джава Collections.asLifoQueue function comments
- джава Collections.asLifoQueue - аргументы и возвращаемое значение
- Функция java Collections.asLifoQueue - описание
- Collections.asLifoQueue - примеры
- Collections.asLifoQueue - похожие методы на java
- Collections.asLifoQueue на javascript, c#, python, php
- Collections.asLifoQueue изменения java
- Примеры Collections.asLifoQueue на джава