Guia para Guava MinMaxPriorityQueue e EvictingQueue
1. Overview
Neste artigo, veremos as construçõesEvictingQueue, eMinMaxPriorityQueue da biblioteca Guava. OEvictingQueue é uma implementação do conceito de buffer circular. OMinMaxPriorityQueue nos dá acesso ao seu menor e maior elemento usando oComparator. fornecido
2. EvictingQueue
Vamos começar com a construção - ao construir uma instância da fila, precisamos fornecer o tamanho máximo da fila como argumento.
Quando queremos adicionar um novo item aEvictingQueue ethe queue is full, it automatically evicts an element from its head.
Ao comparar com o comportamento da fila padrão, adicionar um elemento à fila completa não bloqueia, mas remove o elemento principal e adiciona um novo item à cauda.
Podemos imaginar oEvictingQueue como um anel ao qual estamos inserindo elementos apenas para anexar. Se houver um elemento na posição na qual queremos adicionar um novo elemento, simplesmente substituiremos o elemento existente na posição especificada.
Vamos construir uma instância deEvictingQueue com o tamanho máximo de 10. Em seguida, adicionaremos 10 elementos a ele:
Queue evictingQueue = EvictingQueue.create(10);
IntStream.range(0, 10)
.forEach(evictingQueue::add);
assertThat(evictingQueue)
.containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
Se tivéssemos a implementação de fila padrão, a adição de um novo item à fila completa bloqueará o produtor.
Esse não é o caso da implementação deEvictingQueue. A adição de um novo elemento fará com que a cabeça seja removida e o novo elemento será adicionado à cauda:
evictingQueue.add(100);
assertThat(evictingQueue)
.containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 100);
UsandoEvictingQueue como buffer circular, podemos criar programas concorrentes muito eficientes.
3. MinMaxPriorityQueue
OMinMaxPriorityQueue fornece acesso em tempo constante aos seus menores e maiores elementos.
Para obter o mínimo de elemento, precisamos chamar o métodopeekFirst(). Para obter o maior elemento, podemos chamar o métodopeekLast(). Observe que eles não removem elementos de uma fila, eles apenas o recuperam.
A ordenação dos elementos é feita peloComparator que precisa ser passado para o construtor desta fila.
Digamos que temos uma classeCustomClass que tem um campovalue do tipo inteiro:
class CustomClass {
private Integer value;
// standard constructor, getters and setters
}
Vamos criar umMinMaxPriorityQueue que usará o comparador nos tiposint. A seguir, adicionaremos 10 objetos do tipoCustomClass à fila:
MinMaxPriorityQueue queue = MinMaxPriorityQueue
.orderedBy(Comparator.comparing(CustomClass::getValue))
.maximumSize(10)
.create();
IntStream
.iterate(10, i -> i - 1)
.limit(10)
.forEach(i -> queue.add(new CustomClass(i)));
Devido às características doMinMaxPriorityQueuee passadoComparator,, o elemento no início da fila será igual a 1 e o elemento na extremidade da fila será igual a 10:
assertThat(
queue.peekFirst().getValue()).isEqualTo(1);
assertThat(
queue.peekLast().getValue()).isEqualTo(10);
Como a capacidade da nossa fila é 10 e adicionamos 10 elementos, a fila está cheia. A adição de um novo elemento fará com que o último elemento da fila seja removido. Vamos adicionar umCustomClass comvalue igual a -1:
queue.add(new CustomClass(-1));
Após essa ação, o último elemento da fila será excluído e o novo item no final será igual a 9. A nova cabeça será -1, pois este é o novo elemento mínimo de acordo com osComparator que passamos quando construímos nossa fila:
assertThat(
queue.peekFirst().getValue()).isEqualTo(-1);
assertThat(
queue.peekLast().getValue()).isEqualTo(9);
De acordo com a especificação doMinMaxPriorityQueue,in case the queue is full, adding an element that is greater than the currently greatest element will remove that same element – effectively ignoring it.
Vamos adicionar um número 100 e testar se esse item está na fila após a operação:
queue.add(new CustomClass(100));
assertThat(queue.peekFirst().getValue())
.isEqualTo(-1);
assertThat(queue.peekLast().getValue())
.isEqualTo(9);
Como vemos, o primeiro elemento da fila ainda é igual a -1 e o último é igual a 9. Portanto, a adição de um número inteiro foi ignorada, pois é maior o elemento que já é maior na fila.
4. Conclusão
Neste artigo, demos uma olhada na construçãoEvictingQueueeMinMaxPriorityQueue da biblioteca Guava.
Vimos como usarEvictingQueue como buffer circular para implementar programas muito eficientes.
UsamosMinMaxPriorityQueue combinado comComparator para ter o acesso de tempo constante ao seu menor e maior elemento.
É importante lembrar as características de ambas as filas apresentadas, pois adicionar um novo elemento a elas substituirá um elemento que já está na fila. Isso é contrário às implementações de fila padrão, em que adicionar um novo elemento à fila completa bloqueará o encadeamento do produtor ou lançará uma exceção.
A implementação de todos esses exemplos e trechos de código pode ser encontrada emGitHub project - este é um projeto Maven, portanto, deve ser fácil de importar e executar como está.