Câu trả lời:
Không có triển khai hiện có trong Ngôn ngữ Java và Thời gian chạy. Tất cả các hàng đợi mở rộng AbstractQueue và tài liệu của nó nêu rõ rằng việc thêm một phần tử vào hàng đợi đầy đủ luôn kết thúc bằng một ngoại lệ. Sẽ là tốt nhất (và khá đơn giản) để bọc Hàng đợi vào một lớp của riêng bạn để có chức năng bạn cần.
Một lần nữa, vì tất cả các hàng đợi là con của AbstractQueue, chỉ cần sử dụng nó làm kiểu dữ liệu nội bộ của bạn và bạn sẽ có một triển khai linh hoạt chạy trong hầu như không có thời gian :-)
CẬP NHẬT:
Như được phác thảo dưới đây, có hai triển khai mở có sẵn (câu trả lời này khá cũ, folks!), Xem câu trả lời này để biết chi tiết.
collection.deque
với chỉ định maxlen
.
Trên thực tế LinkedHashMap thực hiện chính xác những gì bạn muốn. Bạn cần ghi đè removeEldestEntry
phương thức.
Ví dụ cho hàng đợi có tối đa 10 phần tử:
queue = new LinkedHashMap<Integer, String>()
{
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest)
{
return this.size() > 10;
}
};
Nếu "removeEldestEntry" trả về đúng, mục nhập lớn nhất sẽ bị xóa khỏi bản đồ.
Từ câu hỏi trùng lặp của riêng tôi với câu trả lời đúng này , tôi đã học được hai:
Tôi đã sử dụng năng suất của ổi EvictingQueue
, hoạt động tốt.
Để khởi tạo một EvictingQueue
cuộc gọi phương thức tĩnh nhà máy create
và chỉ định kích thước tối đa của bạn.
EvictingQueue< Person > people = com.google.common.collect.EvictingQueue.create( 100 ) ; // Set maximum size to 100.
CircularFifoQueue
liên kết đã chết, sử dụng thay vì commons.apache.org/proper/commons-collections/apidocs/org/
Tôi chỉ thực hiện một hàng đợi kích thước cố định theo cách này:
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)
Đây là những gì tôi đã làm với Queue
bọc LinkedList
, Nó có kích thước cố định mà tôi đưa ra ở đây là 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");
.....
Lớp này thực hiện công việc bằng cách sử dụng thành phần thay vì kế thừa (các câu trả lời khác ở đây) sẽ loại bỏ khả năng tác dụng phụ nhất định (như được Josh Bloch trình bày trong Essential Java). Việc cắt danh sách LinkedList cơ bản xảy ra trên các phương thức add, addAll và 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);
}
}
Kết quả sử dụng và kiểm tra:
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]
}
Âm thanh giống như một Danh sách thông thường trong đó phương thức add chứa một đoạn bổ sung sẽ cắt bớt danh sách nếu quá dài.
Nếu điều đó quá đơn giản, thì có lẽ bạn cần chỉnh sửa mô tả vấn đề của mình.
Cũng xem câu hỏi SO này , hoặc ArrayBlockingQueue (hãy cẩn thận về việc chặn, điều này có thể không mong muốn trong trường hợp của bạn).
Nó không hoàn toàn rõ ràng những yêu cầu bạn có mà dẫn bạn đặt câu hỏi này. Nếu bạn cần một cấu trúc dữ liệu có kích thước cố định, bạn cũng có thể muốn xem xét các chính sách bộ đệm khác nhau. Tuy nhiên, vì bạn có một hàng đợi, tôi đoán tốt nhất là bạn đang tìm kiếm một số loại chức năng của bộ định tuyến. Trong trường hợp đó, tôi sẽ đi với bộ đệm vòng: một mảng có chỉ mục đầu tiên và cuối cùng. Bất cứ khi nào một phần tử được thêm vào, bạn chỉ cần tăng chỉ số phần tử cuối cùng và khi một phần tử được loại bỏ, hãy tăng chỉ số phần tử đầu tiên. Trong cả hai trường hợp, phép cộng được thực hiện theo kích thước mảng và đảm bảo tăng chỉ số khác khi cần, nghĩa là khi hàng đợi đầy hoặc trống.
Ngoài ra, nếu đó là một ứng dụng loại bộ định tuyến, bạn cũng có thể muốn thử nghiệm một thuật toán như Thả sớm ngẫu nhiên (ĐỎ), loại bỏ các yếu tố khỏi hàng đợi một cách ngẫu nhiên ngay cả trước khi nó được lấp đầy. Trong một số trường hợp, RED đã được tìm thấy có hiệu suất tổng thể tốt hơn so với phương pháp đơn giản cho phép hàng đợi lấp đầy trước khi thả.
Tôi nghĩ rằng câu trả lời phù hợp nhất là từ câu hỏi khác này .
Bộ sưu tập Apache commons 4 có một tròn trònFifoQueue , đó là những gì bạn đang tìm kiếm. Trích dẫn javadoc:
ThongFifoQueue là hàng đợi vào trước xuất trước với kích thước cố định thay thế phần tử cũ nhất của nó nếu đầy đủ.
Một giải pháp đơn giản, bên dưới là Hàng đợi của "Chuỗi"
LinkedHashMap<Integer, String> queue;
int queueKeysCounter;
queue.put(queueKeysCounter++, "My String");
queueKeysCounter %= QUEUE_SIZE;
Lưu ý rằng điều này sẽ không duy trì Thứ tự của các mục trong Hàng đợi, nhưng nó sẽ thay thế mục nhập cũ nhất.
Như đã khuyên trong các OOP rằng chúng ta nên ưu tiên Thành phần hơn Kế thừa
Đây là giải pháp của tôi giữ điều đó trong tâm trí.
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();
}
}