在Java中保存最后N个元素的大小限制队列
关于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 stdlib中没有标准的实现,但在Apache Commons中可能有这样的一个呢?
Apache公共收集4有一个CircularFifoQueue <>这是你在找什么。 引用javadoc:
CircularFifoQueue是一个固定大小的先进先出队列,如果已满,它将replace其最早的元素。
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 ,它基本上是没有generics的东西。
更新 :支持generics的公共collections版本4发布后的更新答案。
Guava现在有一个EvictingQueue , 一个非阻塞队列,当尝试向队列中添加新元素并且已满时,会自动从队列头部 逐出 元素。
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解决scheme。 但是我会另外保存并返回super.add(o)的值!
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; } }
使用组合不扩展(是的,我的意思是扩展,如在Java中的扩展关键字的引用,是的,这是inheritance)。 组合是更高级的,因为它完全屏蔽了你的实现,允许你改变实现而不影响你的类的用户。
我build议尝试这样的事情(我直接input到这个窗口,所以购买者要小心语法错误):
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
一个更好的select(基于Asaf的答案)可能是将Apache Collections CircularFifoBuffer与一个generics类包装起来。 例如:
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操作,直到空间空闲(由其他线程删除)。
据我所知,你的微不足道的实现是获得这种行为的最简单的方法。
您可以使用来自Google Guava的来自javadoc的MinMaxPriorityQueue :
最小最大优先级队列可以configuration为最大大小。 如果是这样,每当队列的大小超过该值时,队列将根据其比较器(可能是刚刚添加的元素)自动删除其最大元素。 这与传统的有界队列不同,当队列满时阻塞或拒绝新的元素。
另一个可能来自Apache Commons的LRUMap。
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/LRUMap.html
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; } }