Відповіді:
Немає існуючої реалізації в мові та режимі виконання Java. Усі черги розширюють AbstractQueue , і її документ чітко зазначає, що додавання елемента до повної черги завжди закінчується винятком. Найкраще було б (і досить просто) загорнути Чергу в свій власний клас, щоб мати необхідну функціональність.
Ще раз, оскільки всі черги є дітьми AbstractQueue, просто використовуйте це як свій внутрішній тип даних, і у вас повинна бути гнучка реалізація, яка працює практично за короткий час :-)
ОНОВЛЕННЯ:
Як зазначено нижче, доступні дві відкриті реалізації (ця відповідь досить стара, люди!), Детальну інформацію див. У цій відповіді .
collection.deque
із зазначеним maxlen
.
Насправді LinkedHashMap робить саме те, що ви хочете. Вам потрібно перекрити removeEldestEntry
метод.
Приклад для черги з максимум 10 елементами:
queue = new LinkedHashMap<Integer, String>()
{
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest)
{
return this.size() > 10;
}
};
Якщо "RemoveEldestEntry" повертає значення true, найстарший запис видаляється з карти.
З власного дублюючого запитання з цією правильною відповіддю я дізнався про два:
Я продуктивно використовував гуаву EvictingQueue
, працював добре.
Для отримання екземпляра EvictingQueue
виклику статичним заводським методом create
та вкажіть максимальний розмір.
EvictingQueue< Person > people = com.google.common.collect.EvictingQueue.create( 100 ) ; // Set maximum size to 100.
CircularFifoQueue
посилання мертве, замість цього використовуйте commons.apache.org/proper/commons-collections/apidocs/org/…
Я просто реалізував чергу фіксованого розміру таким чином:
public class LimitedSizeQueue<K> extends ArrayList<K> {
private int maxSize;
public LimitedSizeQueue(int size){
this.maxSize = size;
}
public boolean add(K k){
boolean r = super.add(k);
if (size() > maxSize){
removeRange(0, size() - maxSize);
}
return r;
}
public K getYoungest() {
return get(size() - 1);
}
public K getOldest() {
return get(0);
}
}
removeRange(0, size() - maxSize)
Це те, що я зробив із Queue
загорнутою LinkedList
, це розмір фіксованого розміру, який я надаю ось 2;
public static Queue<String> pageQueue;
pageQueue = new LinkedList<String>(){
private static final long serialVersionUID = -6707803882461262867L;
public boolean add(String object) {
boolean result;
if(this.size() < 2)
result = super.add(object);
else
{
super.removeFirst();
result = super.add(object);
}
return result;
}
};
....
TMarket.pageQueue.add("ScreenOne");
....
TMarket.pageQueue.add("ScreenTwo");
.....
Цей клас виконує завдання, використовуючи композицію замість успадкування (інші відповіді тут), яка виключає можливість певних побічних ефектів (як охоплює Джош Блох у Essential Java). Обрізання базового LinkedList відбувається за методами додавання, додавання та пропозиції.
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
public class LimitedQueue<T> implements Queue<T>, Iterable<T> {
private final int limit;
private final LinkedList<T> list = new LinkedList<T>();
public LimitedQueue(int limit) {
this.limit = limit;
}
private boolean trim() {
boolean changed = list.size() > limit;
while (list.size() > limit) {
list.remove();
}
return changed;
}
@Override
public boolean add(T o) {
boolean changed = list.add(o);
boolean trimmed = trim();
return changed || trimmed;
}
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<T> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends T> c) {
boolean changed = list.addAll(c);
boolean trimmed = trim();
return changed || trimmed;
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public void clear() {
list.clear();
}
@Override
public boolean offer(T e) {
boolean changed = list.offer(e);
boolean trimmed = trim();
return changed || trimmed;
}
@Override
public T remove() {
return list.remove();
}
@Override
public T poll() {
return list.poll();
}
@Override
public T element() {
return list.element();
}
@Override
public T peek() {
return list.peek();
}
}
public class CircularQueue<E> extends LinkedList<E> {
private int capacity = 10;
public CircularQueue(int capacity){
this.capacity = capacity;
}
@Override
public boolean add(E e) {
if(size() >= capacity)
removeFirst();
return super.add(e);
}
}
Використання та результат тесту:
public static void main(String[] args) {
CircularQueue<String> queue = new CircularQueue<>(3);
queue.add("a");
queue.add("b");
queue.add("c");
System.out.println(queue.toString()); //[a, b, c]
String first = queue.pollFirst(); //a
System.out.println(queue.toString()); //[b,c]
queue.add("d");
queue.add("e");
queue.add("f");
System.out.println(queue.toString()); //[d, e, f]
}
Звучить як звичайний Список, де метод додавання містить додатковий фрагмент, який скорочує список, якщо він занадто довгий.
Якщо це занадто просто, вам, ймовірно, потрібно відредагувати опис проблеми.
Також дивіться це питання SO , або ArrayBlockingQueue (будьте уважні щодо блокування, це може бути небажаним у вашому випадку).
Не зовсім зрозуміло, які вимоги ви зумовили, щоб ви поставили це питання. Якщо вам потрібна структура даних фіксованого розміру, ви також можете переглянути різні політики кешування. Однак, оскільки у вас є черга, я найкраще здогадуюсь, що ви шукаєте певний тип функціональності маршрутизатора. У такому випадку я б пішов з буфером кільця: масивом, який має перший і останній індекс. Щоразу, коли елемент додається, ви просто збільшуєте індекс останнього елемента, а коли елемент видаляєте, збільшуйте індекс першого елемента. В обох випадках додавання виконується за розміром масиву і обов'язково збільшується інший індекс, коли це необхідно, тобто коли черга повна або порожня.
Крім того, якщо це програма типу маршрутизатора, ви також можете поекспериментувати з таким алгоритмом, як Random Early Dropping (RED), який викидає елементи з черги випадковим чином ще до того, як він заповниться. В деяких випадках було виявлено, що RED має кращі показники загальної продуктивності, ніж простий метод, що дозволяє черзі заповнюватись, перш ніж випадати.
Я думаю, що найкраща відповідь - це саме з цього питання .
Колекція Apache commons 4 має CircularFifoQueue, яку саме ви шукаєте. Цитуючи javadoc:
CircularFifoQueue - це черга, що перебуває на першому місці, із фіксованим розміром, яка замінює її найстаріший елемент, якщо він заповнений.
Просте рішення, нижче - черга "Рядок"
LinkedHashMap<Integer, String> queue;
int queueKeysCounter;
queue.put(queueKeysCounter++, "My String");
queueKeysCounter %= QUEUE_SIZE;
Зауважте, що це не підтримує порядок елементів у черзі, але це замінить найдавніший запис.
Як рекомендується в ООП, ми повинні віддавати перевагу складу над спадщиною
Тут моє рішення, враховуючи це.
package com.choiceview;
import java.util.ArrayDeque;
class Ideone {
public static void main(String[] args) {
LimitedArrayDeque<Integer> q = new LimitedArrayDeque<>(3);
q.add(1);
q.add(2);
q.add(3);
System.out.println(q);
q.add(4);
// First entry ie 1 got pushed out
System.out.println(q);
}
}
class LimitedArrayDeque<T> {
private int maxSize;
private ArrayDeque<T> queue;
private LimitedArrayDeque() {
}
public LimitedArrayDeque(int maxSize) {
this.maxSize = maxSize;
queue = new ArrayDeque<T>(maxSize);
}
public void add(T t) {
if (queue.size() == maxSize) {
queue.removeFirst();
}
queue.add(t);
}
public boolean remove(T t) {
return queue.remove(t);
}
public boolean contains(T t) {
return queue.contains(t);
}
@Override
public String toString() {
return queue.toString();
}
}