web-dev-qa-db-ja.com

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 stdlibsには標準の実装はありませんが、Apache Commonsにあるのかもしれません。

182
GreyCat

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 を使用できます。これは基本的にジェネリックなしで同じものです。

Update:ジェネリックをサポートするcommons collectionsバージョン4のリリース後に回答を更新しました。

155
Asaf

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]
82
Miguel

@FractalizeRソリューションが好きです。しかし、さらに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;
    }
}
11
RenaudBlue

拡張ではない構成を使用します(はい、つまり、Javaのextendsキーワードへの参照のように拡張します。はい、これは継承です)。構成は実装を完全に保護し、クラスのユーザーに影響を与えることなく実装を変更できるため、構成はより優れています。

次のようなものを試すことをお勧めします(このウィンドウに直接入力しているので、買い手は構文エラーに注意してください):

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

より良いオプション(Asafの回答に基づく)は、 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
}
5
DwB

私が知っている唯一のスペースが限られていることは、BlockingQueueインターフェース(例えばArrayBlockingQueueクラスによって実装されます)-しかし、埋められても最初の要素を削除せず、代わりにスペースが空くまでput操作をブロックします(他のスレッドによって削除されます) )。

私の知る限り、あなたの些細な実装がそのような振る舞いを得る最も簡単な方法です。

4
flolo
3
rich

Javadocの MinMaxPriorityQueue from Google Guava を使用できます。

Min-max優先度キューは、最大サイズで構成できます。その場合、キューのサイズがその値を超えるたびに、キューはそのコンパレータ(追加されたばかりの要素である可能性がある)に従って最大の要素を自動的に削除します。これは、新しい要素がいっぱいになるとブロックまたは拒否する従来の境界キューとは異なります。

2
moritz