Risposte:
Non esiste un'implementazione esistente in Java Language and Runtime. Tutte le code estendono AbstractQueue e il relativo documento afferma chiaramente che l'aggiunta di un elemento a una coda completa termina sempre con un'eccezione. Sarebbe meglio (e abbastanza semplice) avvolgere una coda in una classe tutta tua per avere le funzionalità di cui hai bisogno.
Ancora una volta, poiché tutte le code sono figli di AbstractQueue, utilizzale semplicemente come tipo di dati interno e dovresti avere un'implementazione flessibile in esecuzione praticamente in un batter d'occhio :-)
AGGIORNARE:
Come indicato di seguito, ci sono due implementazioni aperte disponibili (questa risposta è piuttosto vecchia, gente!), Vedere questa risposta per i dettagli.
collection.deque
con uno specificato maxlen
.
In realtà LinkedHashMap fa esattamente quello che vuoi. Devi sovrascrivere il removeEldestEntry
metodo.
Esempio per una coda con massimo 10 elementi:
queue = new LinkedHashMap<Integer, String>()
{
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest)
{
return this.size() > 10;
}
};
Se "removeEldestEntry" restituisce true, la voce più vecchia viene rimossa dalla mappa.
Dalla mia domanda duplicata con questa risposta corretta , ho appreso di due:
Ho fatto un uso produttivo della Guava EvictingQueue
, ha funzionato bene.
Per creare un'istanza di una EvictingQueue
chiamata il metodo factory statico create
e specificare la dimensione massima.
EvictingQueue< Person > people = com.google.common.collect.EvictingQueue.create( 100 ) ; // Set maximum size to 100.
CircularFifoQueue
il link è morto, usa invece commons.apache.org/proper/commons-collections/apidocs/org/…
Ho appena implementato una coda di dimensioni fisse in questo modo:
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)
Questo è quello che ho fatto con Queue
avvolto LinkedList
, è di dimensioni fisse che do qui è 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");
.....
Questa classe fa il lavoro usando la composizione invece dell'ereditarietà (altre risposte qui) che rimuove la possibilità di alcuni effetti collaterali (come coperto da Josh Bloch in Essential Java). Il taglio della LinkedList sottostante si verifica sui metodi add, addAll e offer.
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);
}
}
Utilizzo e risultati del test:
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]
}
Sembra un normale elenco in cui il metodo add contiene un frammento aggiuntivo che tronca l'elenco se diventa troppo lungo.
Se è troppo semplice, probabilmente dovrai modificare la descrizione del tuo problema.
Vedi anche questa domanda SO , o ArrayBlockingQueue ( fai attenzione al blocco, questo potrebbe essere indesiderato nel tuo caso).
Non è del tutto chiaro quali siano i requisiti che ti hanno portato a porre questa domanda. Se hai bisogno di una struttura di dati di dimensioni fisse, potresti anche voler esaminare diversi criteri di memorizzazione nella cache. Tuttavia, poiché hai una coda, la mia ipotesi migliore è che stai cercando un tipo di funzionalità del router. In tal caso, andrei con un buffer ad anello: un array che ha un primo e l'ultimo indice. Ogni volta che viene aggiunto un elemento, è sufficiente incrementare l'ultimo indice dell'elemento e quando un elemento viene rimosso, incrementare il primo indice dell'elemento. In entrambi i casi, l'addizione viene eseguita in base alla dimensione dell'array e assicurarsi di incrementare l'altro indice quando necessario, ovvero quando la coda è piena o vuota.
Inoltre, se si tratta di un'applicazione di tipo router, potresti anche voler sperimentare un algoritmo come Random Early Dropping (RED), che elimina gli elementi dalla coda in modo casuale anche prima che si riempia. In alcuni casi, è stato riscontrato che RED ha prestazioni complessive migliori rispetto al semplice metodo per consentire il riempimento della coda prima di rilasciare.
Penso che la risposta migliore sia da questa altra domanda .
Le raccolte 4 di Apache commons hanno un CircularFifoQueue che è quello che stai cercando. Citando il javadoc:
CircularFifoQueue è una coda first-in first-out con una dimensione fissa che sostituisce il suo elemento più vecchio se pieno.
Una soluzione semplice, di seguito è una coda di "String"
LinkedHashMap<Integer, String> queue;
int queueKeysCounter;
queue.put(queueKeysCounter++, "My String");
queueKeysCounter %= QUEUE_SIZE;
Si noti che ciò non manterrà l'ordine degli articoli nella coda, ma sostituirà la voce più vecchia.
Come è stato consigliato negli OOP, dovremmo preferire la composizione all'ereditarietà
Ecco la mia soluzione tenendo presente questo.
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();
}
}