Има ли еквивалент на Guava на Apache Commons CircularFifoBuffer?

Имам нужда от структура от данни, която може ефективно да буферира определен брой елементи в FIFO ред.

Както бе споменато в този въпрос, Apache Commons има CircularFifoBuffer, но за съжаление не е генериран. Някои разклонения съществуват, но не съм сигурен в състоянието им на поддръжка.

Тъй като Guava е основната библиотека за нуждите ми от колекции, се чудя: има ли добра алтернатива в Guava? Ако не, трябва ли да го внедря в моя проект, базиран на CircularFifoBuffer на Apache Commons?


person Etienne Neveu    schedule 09.01.2013    source източник
comment
Какво ви трябва от кръглата част? Безкрайна итерация?   -  person fge    schedule 09.01.2013
comment
Кръговата част се отнася до общата реализация, която е масив с два индекса към началото и края на буфера. Когато масивът е пълен, структурата от данни започва да записва отново в началото на масива, като презаписва най-старите елементи по кръгов начин. Готиното при тази реализация е, че не е необходимо да създавате ненужни записи като в LinkedList, което намалява събирането на боклук. Тъй като не е необходимо да премахвам елементи в средата на буфера, това изглежда като перфектно пасване.   -  person Etienne Neveu    schedule 09.01.2013
comment
Да, съжалявам, отидох и прочетох javadoc едва след като публикувах първия коментар ;) Изглежда, че Guava няма колекции с ограничен размер, така че вероятно сте осъдени да внедрите това сами :/   -  person fge    schedule 09.01.2013
comment
Задължителна функция ли е, когато е пълен, най-старият запис да се презаписва? Ако е така, ще премахна отговора си, тъй като ArrayBlockingQueue ще блокира, когато е пълен.   -  person SimonC    schedule 09.01.2013
comment
Е, имам два случая на употреба. 1) Искам да поддържам подвижен буфер от последните N събития, обработени от нашето приложение, и да регистрирам тези събития, когато бъде хвърлено изключение. В идеалния случай буферът трябва автоматично да презапише най-старото събитие, вместо да го прави ръчно. 2) Имам трансформация, която буферира последните 10 събития. Когато буферът е пълен, искам да обработя най-старото събитие и да го премахна от буфера. Така че премахването е ръчно в този случай.   -  person Etienne Neveu    schedule 09.01.2013


Отговори (4)


Стартиране на Guava 15.0 - можете да използвате Изгонваща опашка

person MosheElisha    schedule 06.05.2013

Не виждам нищо подобно в Guava, но какво ще кажете за ForwardingQueue, изграден около ArrayDeque където проверявате капацитета на add(), offer() и т.н. и remove() стари записи, ако вече е пълен?

person Frank Pavageau    schedule 09.01.2013
comment
Наистина харесвам това решение, защото поведението на ArrayDeque всъщност е много близко до това на CircularFifoBuffer, след като го украсите, за да премахнете най-стария елемент, когато е пълен. Класът няма заключване/синхронизация, което е добре, тъй като не ме интересува безопасността на нишката. Единственият недостатък, който виждам, е, че основният масив може да е по-голям от необходимото, тъй като размерът му трябва да е степен на 2. Но това е преждевременна оптимизация :) - person Etienne Neveu; 09.01.2013

Commons-Collections with Generics (maven link) е правилният начин, ако искате да използвате Apache Collections с генерични (и съдържа работещ CircularFifoBuffer<E> клас).

От друга страна, както казва @FrankPavageau, можете да използвате своя собствена ForwardingQueue реализация. Наивен подход (с място за допълнителни оптимизации) би бил нещо подобно:

static class BoundedQueue<E> extends ForwardingQueue<E> {

  private final Queue<E> delegate;
  private final int capacity;

  public BoundedQueue(final int capacity) {
    this.delegate = 
        new ArrayDeque<E>(capacity); // specifying initial capacity is optional
    this.capacity = capacity;
  }

  @Override
  protected Queue<E> delegate() {
    return delegate;
  }

  @Override
  public boolean add(final E element) {
    if (size() >= capacity) {
      delegate.poll();
    }
    return delegate.add(element);
  }

  @Override
  public boolean addAll(final Collection<? extends E> collection) {
    return standardAddAll(collection);
  }

  @Override
  public boolean offer(final E o) {
    return standardOffer(o);
  }

}

Употреба:

final BoundedQueue<Integer> boundedQueue = new BoundedQueue<Integer>(3);
boundedQueue.add(1);
System.out.println(boundedQueue); // [1]
boundedQueue.add(2);
System.out.println(boundedQueue); // [1, 2]
boundedQueue.add(3);
System.out.println(boundedQueue); // [1, 2, 3]
boundedQueue.add(4);
System.out.println(boundedQueue); // [2, 3, 4]
boundedQueue.addAll(Arrays.asList(5, 6, 7, 8));
System.out.println(boundedQueue); // [6, 7, 8]
((Queue<Integer>) boundedQueue).offer(9);
System.out.println(boundedQueue); // [7, 8, 9]
person Xaerxess    schedule 09.01.2013
comment
да Ще използвам CircularFifoBuffer, за да разреша текущия си проблем. Промених зависимостта си от commons-collections:commons-collections:3.2 на net.sourceforge.collections:collections-generic:4.01 след известно търсене (няма много документация). Надявам се обаче официалната генерирана версия на commons-collections да бъде пусната скоро. Като изключим това, би било страхотно, ако такава структура от данни може да бъде добавена към Guava. - person Etienne Neveu; 09.01.2013
comment
Искането за подобна функция е изпратено като проблем №336. Означете със звезда и/или коментирайте, за да видите дали ще бъде приложено. - person Xaerxess; 09.01.2013
comment
Guava току-що отвори EvictingQueue: code.google.com/p/ guava-libraries/source/ Изглежда като това, от което имах нужда :) - person Etienne Neveu; 12.02.2013
comment
Хубаво, но няма да е там преди 15.0... Освен това измислиха по-добро име от моето ;) - person Xaerxess; 12.02.2013

ArrayBlockingQueue на Java предлага циркуляр с фиксиран размер буфер.

person SimonC    schedule 09.01.2013
comment
enevu споменава в коментар, че когато масивът е пълен, структурата от данни започва да записва отново в началото на масива, като презаписва най-старите елементи. ArrayBlockingQueue не прави това. Въпреки това не би трябвало да е твърде трудно да го промените. - person Tom Anderson; 09.01.2013
comment
ArrayBlockingQueue е доста близо до това, което искам, но нямам нужда от синхронизация. Мисля, че предпочитам ArrayDeque. Но определено е добър избор в едновременна среда. Фактът, че блокира, когато е пълен, не е толкова проблематичен, тъй като всъщност е доста лесно да го декорирате, за да премахнете най-старите елементи, когато е пълен. - person Etienne Neveu; 09.01.2013
comment
Този отговор е неправилен. При добавяне на елемент извън лимита, ArrayBlockingQueue блокира (оттук и името), докато CircularFifoQueue изпуска най-стария елемент. За да цитирам документа за ArrayBlockingQueue: Attempts to put an element into a full queue will result in the operation blocking - person Basil Bourque; 11.02.2014
comment
@BasilBourque, как този отговор е неправилен? Въпросът беше има ли добра алтернатива в Guava?, а не има ли алтернатива, която е функционално идентична по всеки един начин. Освен това OP заявява директно над вашия коментар. Фактът, че блокира, когато е пълен, не е толкова проблематичен. Моля, прочетете другите коментари, преди да публикувате. - person SimonC; 11.02.2014