Saco das coleções de Apache Commons
1. Introdução
Neste artigo rápido, vamos nos concentrar em como usar a coleçãoBag do Apache.
Leitura adicional:
Apache Commons BeanUtils
Aprenda a usar o Apache Commons BeanUtils para operações de bean comum.
Apache Commons IO
Um guia rápido e prático da biblioteca de código-fonte aberto Apache Commons IO para Java, cobrindo muitos de seus recursos mais conhecidos.
Introdução ao Apache Commons Text
Aprenda a usar o Apache Commons Text para operações comuns de String.
2. Dependência do Maven
Antes de começar, precisamos importar as dependências mais recentes deMaven Central:
org.apache.commons
commons-collections4
4.1
3. Sacos vs coleções
Simplificando,Bag é uma coleção que permite armazenar vários itens junto com sua contagem de repetição:
public void whenAdded_thenCountIsKept() {
Bag bag = new HashBag<>(
Arrays.asList(1, 2, 3, 3, 3, 1, 4));
assertThat(2, equalTo(bag.getCount(1)));
}
3.1. Violações do ContratoCollection
Ao ler a documentação da API deBag, podemos notar que alguns métodos estão marcados como violando o contrato de coleção padrão do Java.
Por exemplo, quando usamos uma APIadd() de uma coleção Java, recebemostrue mesmo se o item já estiver na coleção:
Collection collection = new ArrayList<>();
collection.add(1);
assertThat(collection.add(1), is(true));
A mesma API de uma implementaçãoBag retornará umfalse quando adicionarmos um elemento que já está disponível na coleção:
Bag bag = new HashBag<>();
bag.add(1);
assertThat(bag.add(1), is(not(true)));
Para resolver esses problemas, a biblioteca de coleções do Apache fornece um decorador chamadoCollectionBag.. Podemos usar isso para tornar nossas coleções de bolsas compatíveis com o contrato JavaCollection:
public void whenBagAddAPILikeCollectionAPI_thenTrue() {
Bag bag = CollectionBag.collectionBag(new HashBag<>());
bag.add(1);
assertThat(bag.add(1), is((true)));
}
4. Implementações de bolsas
Vamos agora explorar as várias implementações da interfaceBag - dentro da biblioteca de coleções do Apache.
4.1. HashBag
Podemos adicionar um elemento e instruir a API sobre o número de cópias que esse elemento deve ter em nossa coleção de malas:
public void givenAdd_whenCountOfElementsDefined_thenCountAreAdded() {
Bag bag = new HashBag<>();
bag.add(1, 5); // adding 1 five times
assertThat(5, equalTo(bag.getCount(1)));
}
Também podemos excluir um número específico de cópias ou todas as instâncias de um elemento da nossa bolsa:
public void givenMultipleCopies_whenRemove_allAreRemoved() {
Bag bag = new HashBag<>(
Arrays.asList(1, 2, 3, 3, 3, 1, 4));
bag.remove(3, 1); // remove one element, two still remain
assertThat(2, equalTo(bag.getCount(3)));
bag.remove(1); // remove all
assertThat(0, equalTo(bag.getCount(1)));
}
4.2. TreeBag
A implementação deTreeBag funciona como qualquer outra árvore, mantendo adicionalmente a semântica deBag.
Podemos naturalmente classificar uma matriz de inteiros com umTreeBage, em seguida, consultar o número de instâncias que cada elemento individual possui na coleção:
public void givenTree_whenDuplicateElementsAdded_thenSort() {
TreeBag bag = new TreeBag<>(Arrays.asList(7, 5,
1, 7, 2, 3, 3, 3, 1, 4, 7));
assertThat(bag.first(), equalTo(1));
assertThat(bag.getCount(bag.first()), equalTo(2));
assertThat(bag.last(), equalTo(7));
assertThat(bag.getCount(bag.last()), equalTo(3));
}
OTreeBag implementa uma interfaceSortedBag, todas as implementações dessa interface podem usar o decoradorCollectionSortedBag para cumprir o contrato de coleções Java:
public void whenTreeAddAPILikeCollectionAPI_thenTrue() {
SortedBag bag
= CollectionSortedBag.collectionSortedBag(new TreeBag<>());
bag.add(1);
assertThat(bag.add(1), is((true)));
}
4.3. SynchronizedSortedBag
Outra implementação amplamente usada deBag é oSynchronizedSortedBag. Precisamente, este é um decorador sincronizado de uma implementaçãoSortedBag.
Podemos usar este decorador com nossoTreeBag (uma implementação deSortedBag) da seção anterior para sincronizar o acesso à nossa bolsa:
public void givenSortedBag_whenDuplicateElementsAdded_thenSort() {
SynchronizedSortedBag bag = SynchronizedSortedBag
.synchronizedSortedBag(new TreeBag<>(
Arrays.asList(7, 5, 1, 7, 2, 3, 3, 3, 1, 4, 7)));
assertThat(bag.first(), equalTo(1));
assertThat(bag.getCount(bag.first()), equalTo(2));
assertThat(bag.last(), equalTo(7));
assertThat(bag.getCount(bag.last()), equalTo(3));
}
Podemos usar uma combinação de APIs -Collections.synchronizedSortedMap()eTreeMap – para simular o que fizemos aqui comSynchronizedSortedBag.
5. Conclusão
Neste breve tutorial, aprendemos sobre a interfaceBag e suas várias implementações.
Como sempre, o código deste artigo pode ser encontradoover on GitHub.