我有一个流媒体时间序列,我有兴趣保留最后4个元素,这意味着我希望能够弹出第一个,并添加到最后。基本上我需要的是ring buffer。
哪个Java Collection最适合这个?矢量?
答案 0 :(得分:87)
从Apache CircularFifoBuffer考虑Common.Collections。与Queue不同,您不必维护基础集合的有限大小,并在达到限制时将其包装。
Buffer buf = new CircularFifoBuffer(4);
buf.add("A");
buf.add("B");
buf.add("C");
buf.add("D"); //ABCD
buf.add("E"); //BCDE
由于以下属性,CircularFifoBuffer将为您执行此操作:
但是你也应该考虑它的局限性 - 例如,你不能在这个集合中添加缺少的时间序列,因为它不允许空值。
注意:使用当前Common Collections(4. *)时,您必须使用队列。像这样:
Queue buf = new CircularFifoQueue(4);
答案 1 :(得分:43)
自Guava 15。0(2013年9月发布)以来,有EvictingQueue:
非阻塞队列,自动从头部驱逐元素 尝试将新元素添加到队列及其时的队列 已满。必须使用最大大小配置驱逐队列。 每次将元素添加到完整队列时,队列都会自动进行 删除其头部元素。这与传统的有界不同 队列,在满员时阻止或拒绝新元素。
此类不是线程安全的,并且不接受null元素。
使用示例:
EvictingQueue<String> queue = EvictingQueue.create(2);
queue.add("a");
queue.add("b");
queue.add("c");
queue.add("d");
System.out.print(queue); //outputs [c, d]
答案 2 :(得分:16)
从Java 1.6开始,有ArrayDeque
,它实现Queue
并且似乎比LinkedList
更快,内存效率更高,并且没有ArrayBlockingQueue
的线程同步开销{1}}:来自API文档:“当用作堆栈时,此类可能比Stack快,并且在用作队列时比LinkedList更快。”
final Queue<Object> q = new ArrayDeque<Object>();
q.add(new Object()); //insert element
q.poll(); //remove element
答案 3 :(得分:11)
如果您需要
然后您可以这样使用this CircularArrayList for Java(例如):
CircularArrayList<String> buf = new CircularArrayList<String>(4);
buf.add("A");
buf.add("B");
buf.add("C");
buf.add("D"); // ABCD
String pop = buf.remove(0); // A <- BCD
buf.add("E"); // BCDE
String interiorElement = buf.get(i);
所有这些方法都在O(1)中运行。
答案 4 :(得分:5)
前段时间我遇到了同样的问题并且感到很失望,因为我找不到满足我需求的任何解决方案,所以我写了自己的课程。 老实说,我当时确实发现了一些代码,但即使这样也不是我要搜索的,所以我对它进行了调整,现在我正在分享它,就像那段代码的作者那样。
编辑:这是原始(虽然略有不同)代码:CircularArrayList for java
我没有源的链接,因为它是在很久以前,但这里是代码:
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
public class CircularArrayList<E> extends AbstractList<E> implements RandomAccess {
private final int n; // buffer length
private final List<E> buf; // a List implementing RandomAccess
private int leader = 0;
private int size = 0;
public CircularArrayList(int capacity) {
n = capacity + 1;
buf = new ArrayList<E>(Collections.nCopies(n, (E) null));
}
public int capacity() {
return n - 1;
}
private int wrapIndex(int i) {
int m = i % n;
if (m < 0) { // modulus can be negative
m += n;
}
return m;
}
@Override
public int size() {
return this.size;
}
@Override
public E get(int i) {
if (i < 0 || i >= n-1) throw new IndexOutOfBoundsException();
if(i > size()) throw new NullPointerException("Index is greater than size.");
return buf.get(wrapIndex(leader + i));
}
@Override
public E set(int i, E e) {
if (i < 0 || i >= n-1) {
throw new IndexOutOfBoundsException();
}
if(i == size()) // assume leader's position as invalid (should use insert(e))
throw new IndexOutOfBoundsException("The size of the list is " + size() + " while the index was " + i
+". Please use insert(e) method to fill the list.");
return buf.set(wrapIndex(leader - size + i), e);
}
public void insert(E e)
{
int s = size();
buf.set(wrapIndex(leader), e);
leader = wrapIndex(++leader);
buf.set(leader, null);
if(s == n-1)
return; // we have replaced the eldest element.
this.size++;
}
@Override
public void clear()
{
int cnt = wrapIndex(leader-size());
for(; cnt != leader; cnt = wrapIndex(++cnt))
this.buf.set(cnt, null);
this.size = 0;
}
public E removeOldest() {
int i = wrapIndex(leader+1);
for(;;i = wrapIndex(++i)) {
if(buf.get(i) != null) break;
if(i == leader)
throw new IllegalStateException("Cannot remove element."
+ " CircularArrayList is empty.");
}
this.size--;
return buf.set(i, null);
}
@Override
public String toString()
{
int i = wrapIndex(leader - size());
StringBuilder str = new StringBuilder(size());
for(; i != leader; i = wrapIndex(++i)){
str.append(buf.get(i));
}
return str.toString();
}
public E getOldest(){
int i = wrapIndex(leader+1);
for(;;i = wrapIndex(++i)) {
if(buf.get(i) != null) break;
if(i == leader)
throw new IllegalStateException("Cannot remove element."
+ " CircularArrayList is empty.");
}
return buf.get(i);
}
public E getNewest(){
int i = wrapIndex(leader-1);
if(buf.get(i) == null)
throw new IndexOutOfBoundsException("Error while retrieving the newest element. The Circular Array list is empty.");
return buf.get(i);
}
}
答案 5 :(得分:2)
一个非常有趣的项目是破坏者。它有一个环形缓冲区,可以从我在金融应用中的用途中使用。
我检查了Guava的EvictingQueue和ArrayDeque。
ArrayDeque不会限制增长,如果它已满,它会增加一倍的尺寸,因此不会像环形缓冲区一样。
EvictingQueue做了它所承诺的事情,但内部使用Deque来存储东西并且只限制内存。
因此,如果你关心内存受限,那么ArrayDeque并没有完全履行你的诺言。如果您关心对象计数,则EvictingQueue使用内部组合(更大的对象大小)。
可以从jmonkeyengine窃取一个简单且内存效率高的内容。 逐字复制
import java.util.Iterator;
import java.util.NoSuchElementException;
public class RingBuffer<T> implements Iterable<T> {
private T[] buffer; // queue elements
private int count = 0; // number of elements on queue
private int indexOut = 0; // index of first element of queue
private int indexIn = 0; // index of next available slot
// cast needed since no generic array creation in Java
public RingBuffer(int capacity) {
buffer = (T[]) new Object[capacity];
}
public boolean isEmpty() {
return count == 0;
}
public int size() {
return count;
}
public void push(T item) {
if (count == buffer.length) {
throw new RuntimeException("Ring buffer overflow");
}
buffer[indexIn] = item;
indexIn = (indexIn + 1) % buffer.length; // wrap-around
count++;
}
public T pop() {
if (isEmpty()) {
throw new RuntimeException("Ring buffer underflow");
}
T item = buffer[indexOut];
buffer[indexOut] = null; // to help with garbage collection
count--;
indexOut = (indexOut + 1) % buffer.length; // wrap-around
return item;
}
public Iterator<T> iterator() {
return new RingBufferIterator();
}
// an iterator, doesn't implement remove() since it's optional
private class RingBufferIterator implements Iterator<T> {
private int i = 0;
public boolean hasNext() {
return i < count;
}
public void remove() {
throw new UnsupportedOperationException();
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return buffer[i++];
}
}
}
答案 6 :(得分:0)
以前给出的示例都没有完全满足我的需求,因此我编写了自己的队列,允许以下功能:迭代,索引访问,indexOf,lastIndexOf,获取第一,获取最后,提供,剩余容量,扩展容量,出列last,dequeue first,enqueue / add element,dequeue / remove element,subQueueCopy,subArrayCopy,toArray,snapshot,basics like size,remove或contains。
答案 7 :(得分:-3)
使用Queue
Queue<String> qe=new LinkedList<String>();
qe.add("a");
qe.add("b");
qe.add("c");
qe.add("d");
System.out.println(qe.poll()); //returns a
System.out.println(qe.poll()); //returns b
System.out.println(qe.poll()); //returns c
System.out.println(qe.poll()); //returns d
有五种简单的方法
element() - 检索但不删除此文件的头部 队列中。
offer(E o) - 如果是,则将指定的元素插入此队列 可能的。
peek() - 检索但不删除此头部 queue,如果此队列为空,则返回null。
poll() - 检索并删除此队列的头部,或 如果此队列为空,则返回null。