Очередь с ограниченным размером, которая содержит последние N элементов в Java
очень простой и быстрый вопрос о библиотеках Java: есть ли готовый класс, который реализует Queue с фиксированным максимальным размером-т. е. он всегда позволяет добавлять элементы, но он будет молча удалять головные элементы для размещения пространства для новых добавленных элементов.
конечно, это тривиально, чтобы реализовать это вручную:
import java.util.LinkedList;
public class LimitedQueue<E> extends LinkedList<E> {
private int limit;
public LimitedQueue(int limit) {
this.limit = limit;
}
@Override
public boolean add(E o) {
super.add(o);
while (size() > limit) { super.remove(); }
return true;
}
}
насколько я вижу, в Java stdlibs нет стандартной реализации, но может быть, есть один в Apache Commons или что-то вроде это?
8 ответов:
Apache commons collections 4 имеет CircularFifoQueue это то, что вы ищете. Цитируя javadoc:
CircularFifoQueue-это очередь первого входа с фиксированным размером, которая заменяет самый старый элемент, если он заполнен.
import java.util.Queue; import org.apache.commons.collections4.queue.CircularFifoQueue; Queue<Integer> fifo = new CircularFifoQueue<Integer>(2); fifo.add(1); fifo.add(2); fifo.add(3); System.out.println(fifo); // Observe the result: // [2, 3]Если вы используете старую версию коллекций Apache commons (3.X), вы можете использовать CircularFifoBuffer который является в основном то же самое без дженерик.
обновление: обновлен ответ после выпуска commons collections версии 4, которая поддерживает дженерики.
У гуавы теперь есть выселение Queue,неблокирующая очередь, которая автоматически выселяет элементы из головы очереди при попытке добавить новые элементы в очередь, и она заполнена.
import java.util.Queue; import com.google.common.collect.EvictingQueue; Queue<Integer> fifo = EvictingQueue.create(2); fifo.add(1); fifo.add(2); fifo.add(3); System.out.println(fifo); // Observe the result: // [2, 3]
Мне нравится решение @FractalizeR. Но я бы дополнительно сохранил и вернул значение от super.добавить(о)!
public class LimitedQueue<E> extends LinkedList<E> { private int limit; public LimitedQueue(int limit) { this.limit = limit; } @Override public boolean add(E o) { boolean added = super.add(o); while (added && size() > limit) { super.remove(); } return added; } }
использовать композицию не распространяется (да, в смысле расширяется, как в ссылку на ключевое слово extends Java и да это наследство). Композиция лучше, потому что она полностью защищает вашу реализацию, позволяя вам изменять реализацию, не влияя на пользователей вашего класса.
Я рекомендую попробовать что-то вроде этого (я печатаю прямо в это окно, поэтому покупатель остерегается синтаксических ошибок):
public LimitedSizeQueue implements Queue { private int maxSize; private LinkedList storageArea; public LimitedSizeQueue(final int maxSize) { this.maxSize = maxSize; storageArea = new LinkedList(); } public boolean offer(ElementType element) { if (storageArea.size() < maxSize) { storageArea.addFirst(element); } else { ... remove last element; storageArea.addFirst(element); } } ... the rest of this classболее лучший вариант (основанный на ответе мимо Асаф) может быть, чтобы обернуть Apache Collections CircularFifoBuffer С общим классом. Например:
public LimitedSizeQueue<ElementType> implements Queue<ElementType> { private int maxSize; private CircularFifoBuffer storageArea; public LimitedSizeQueue(final int maxSize) { if (maxSize > 0) { this.maxSize = maxSize; storateArea = new CircularFifoBuffer(maxSize); } else { throw new IllegalArgumentException("blah blah blah"); } } ... implement the Queue interface using the CircularFifoBuffer class }
единственное, что я знаю, что имеет ограниченное пространство, - это интерфейс BlockingQueue (который, например, реализован классом ArrayBlockingQueue), но они не удаляют первый элемент, если он заполнен, а вместо этого блокируют операцию put до тех пор, пока пространство не освободится (удаляется другим потоком).
насколько мне известно, ваша тривиальная реализация-это самый простой способ получить такое поведение.
LRUMap-это еще одна возможность, также из Apache Commons.
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/LRUMap.html
можно использовать MinMaxPriorityQueue С Google Guava, из javadoc:
очередь приоритетов min-max может быть настроена с максимальным размером. Если это так, то каждый раз, когда размер очереди превышает это значение, очередь автоматически удаляет свой наибольший элемент в соответствии с его компаратором (который может быть только что добавленным элементом). Это отличается от обычных ограниченных очередей, которые либо блокируют, либо отклоняют новые элементы, когда полный.
public class ArrayLimitedQueue<E> extends ArrayDeque<E> { private int limit; public ArrayLimitedQueue(int limit) { super(limit + 1); this.limit = limit; } @Override public boolean add(E o) { boolean added = super.add(o); while (added && size() > limit) { super.remove(); } return added; } @Override public void addLast(E e) { super.addLast(e); while (size() > limit) { super.removeLast(); } } @Override public boolean offerLast(E e) { boolean added = super.offerLast(e); while (added && size() > limit) { super.pollLast(); } return added; } }
Comments