Introdução às coleções do Eclipse
1. Visão geral
Eclipse Collections é outra estrutura de coleta aprimorada para Java.
Simplificando, ele fornece implementações otimizadas, além de algumas estruturas e recursos de dados adicionais que não são encontrados no Java principal.
A biblioteca fornece implementações mutáveis e imutáveis de todas as estruturas de dados.
2. Dependência do Maven
Vamos começar adicionando a seguinte dependência Maven ao nossopom.xml:
org.eclipse.collections
eclipse-collections
8.2.0
Podemos encontrar a versão mais recente da biblioteca emMaven Central Repository.
3. A grande imagem
3.1. Tipos de coleção básicos
Os tipos básicos de coleção nas Coleções Eclipse são:
-
ListIterable - uma coleção ordenada que mantém a ordem de inserção e permite elementos duplicados. As subinterfaces incluem:MutableList,FixedSizeList eImmutableList. OListIterable implementation is FastList, which is a subclass of MutableList mais comum
-
SetIterable - uma coleção que não permite elementos duplicados. Pode ser classificado ou não. As subinterfaces incluem:SortedSetIterableeUnsortedSetIterable. A implementação não classificada mais comum deSetIterable éUnifiedSet
-
MapIterable - uma coleção de pares de chave / valor. As subinterfaces incluemMutableMap,FixedSizeMap eImmutableMap. Duas implementações comuns sãoUnifiedMapeMutableSortedMap. EnquantoUnifiedMap não mantém nenhuma ordem,MutableSortedMap mantém a ordem natural dos elementos
-
BiMap - uma coleção de pares chave / valor que podem ser iterados em qualquer direção. BiMap estende a interfaceMapIterable
-
Bag - uma coleção não ordenada que permite duplicatas. As subinterfaces incluemMutableBag andFixedSizeBag. A implementação mais comum éHashBag
-
StackIterable - uma coleção que mantém a ordem “último a entrar, primeiro a sair”, iterando através dos elementos na ordem de inserção reversa. As subinterfaces incluemMutableStack eImmutableStack
-
MultiMap - uma coleção de pares de chave / valor que permite vários valores para cada chave
3.2. Coleções primitivas
The framework also provides a huge set of primitive collections; suas implementações são nomeadas de acordo com o tipo que possuem. Existem formas mutáveis, imutáveis, sincronizadas e não modificáveis para cada tipo delas:
-
PrimitivoLists
-
PrimitivoSets
-
PrimitivoStacks
-
PrimitivoBags
-
PrimitivoMaps
-
IntInterval
Há um grande número de formulários de mapas primitivos que cobrem todas as combinações possíveis de chaves primitivas ou de objeto e valores primitivos ou de objeto.
Uma nota rápida - umIntInterval é um intervalo de inteiros que pode ser repetido usando um valor de etapa.
4. Instanciando uma coleção
Para adicionar elementos a umArrayList ouHashSet, instanciamos uma coleção chamando o construtor no-arg e adicionando cada elemento um por um.
Embora ainda possamos fazer isso nas coleções do Eclipse,we can also instantiate a collection and provide all initial elements at the same time in a single line.
Vamos ver como podemos instanciar umFastList:
MutableList list = FastList.newListWith(
"Porsche", "Volkswagen", "Toyota", "Mercedes", "Toyota");
Da mesma forma, podemos instanciar umUnifiedSete adicionar elementos a ele passando os elementos para o método estáticonewSetWith():
Set comparison = UnifiedSet.newSetWith(
"Porsche", "Volkswagen", "Toyota", "Mercedes");
Veja como podemos instanciar umHashBag:
MutableBag bag = HashBag.newBagWith(
"Porsche", "Volkswagen", "Toyota", "Porsche", "Mercedes");
Instanciar mapas e adicionar pares de chave e valor a eles é semelhante. A única diferença é que passamos os pares de chave e valor para o métodonewMapWith() como implementações da interfacePair.
Vamos pegarUnifiedMap como exemplo:
Pair pair1 = Tuples.pair(1, "One");
Pair pair2 = Tuples.pair(2, "Two");
Pair pair3 = Tuples.pair(3, "Three");
UnifiedMap map = new UnifiedMap<>(pair1, pair2, pair3);
Ainda podemos usar a abordagem da API Java Collections:
UnifiedMap map = new UnifiedMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
Já queimmutable collections cannot be modified, they do not have implementations of methods that modify collections, comoadd() eremove().
Coleções não modificáveis, entretanto, nos permitem chamar esses métodos, mas irão lançar umUnsupportedOperationException se o fizermos.
5. Recuperando Elementos de Coleções
Assim como usarLists padrão, os elementos das coleções do EclipseLists podem ser recuperados por seu índice:
list.get(0);
E os valores dos mapas do Eclipse Collections podem ser recuperados usando sua chave:
map.get(0);
Os métodosgetFirst()egetLast() podem ser usados para recuperar o primeiro e o último elemento de uma lista, respectivamente. No caso de outras coleções, eles retornam o primeiro e o último elemento que seriam retornados por um iterador.
map.getFirst();
map.getLast();
Os métodosmax()emin() podem ser usados para obter os valores máximo e mínimo de uma coleção com base na ordem natural.
map.max();
map.min();
6. Iterando sobre uma coleção
O Eclipse Collections fornece várias maneiras de iterar sobre coleções. Vamos ver o que são e como funcionam na prática.
6.1. Filtragem de coleção
O padrão de seleção retorna uma nova coleção que contém elementos de uma coleção que satisfazem uma condição lógica. É essencialmente uma operação de filtragem.
Aqui está um exemplo:
@Test
public void givenListwhenSelect_thenCorrect() {
MutableList greaterThanThirty = list
.select(Predicates.greaterThan(30))
.sortThis();
Assertions.assertThat(greaterThanThirty)
.containsExactly(31, 38, 41);
}
O mesmo pode ser feito usando uma expressão lambda simples:
return list.select(i -> i > 30)
.sortThis();
O padrão de rejeição é o oposto. Retorna uma coleção de todos os elementos que não satisfazem uma condição lógica.
Vamos ver um exemplo:
@Test
public void whenReject_thenCorrect() {
MutableList notGreaterThanThirty = list
.reject(Predicates.greaterThan(30))
.sortThis();
Assertions.assertThat(notGreaterThanThirty)
.containsExactlyElementsOf(this.expectedList);
}
Aqui, rejeitamos todos os elementos maiores que 30.
6.2. O Métodocollect()
O métodocollect retorna uma nova coleção cujos elementos são os resultados retornados pela expressão lambda fornecida - essencialmente, é uma combinação demap()ecollect() da API Stream.
Vamos ver em ação:
@Test
public void whenCollect_thenCorrect() {
Student student1 = new Student("John", "Hopkins");
Student student2 = new Student("George", "Adams");
MutableList students = FastList
.newListWith(student1, student2);
MutableList lastNames = students
.collect(Student::getLastName);
Assertions.assertThat(lastNames)
.containsExactly("Hopkins", "Adams");
}
A coleçãolastNames criada contém os sobrenomes que são coletados da listastudents.
Mas,what if the returned collection is a collection of collections and we do not want to maintain a nested structure?
Por exemplo, se cada aluno tiver vários endereços e precisarmos de uma coleção que contenha os endereços comoStrings em vez de uma coleção de coleções, podemos usar o métodoflatCollect().
Aqui está um exemplo:
@Test
public void whenFlatCollect_thenCorrect() {
MutableList addresses = students
.flatCollect(Student::getAddresses);
Assertions.assertThat(addresses)
.containsExactlyElementsOf(this.expectedAddresses);
}
6.3. Detecção de Elemento
O métododetect encontra e retorna o primeiro elemento que satisfaz uma condição lógica.
Vejamos um exemplo rápido:
@Test
public void whenDetect_thenCorrect() {
Integer result = list.detect(Predicates.greaterThan(30));
Assertions.assertThat(result)
.isEqualTo(41);
}
O métodoanySatisfy determina se algum elemento de uma coleção satisfaz uma condição lógica.
Aqui está um exemplo:
@Test
public void whenAnySatisfiesCondition_thenCorrect() {
boolean result = list.anySatisfy(Predicates.greaterThan(30));
assertTrue(result);
}
Da mesma forma, o métodoallSatisfy determina se todos os elementos de uma coleção satisfazem uma condição lógica.
Vamos ver um exemplo rápido:
@Test
public void whenAnySatisfiesCondition_thenCorrect() {
boolean result = list.allSatisfy(Predicates.greaterThan(0));
assertTrue(result);
}
6.4. O Métodopartition()
O métodopartition aloca cada elemento de uma coleção em uma das duas coleções, dependendo se o elemento satisfaz ou não uma condição lógica.
Vamos ver um exemplo:
@Test
public void whenAnySatisfiesCondition_thenCorrect() {
MutableList numbers = list;
PartitionMutableList partitionedFolks = numbers
.partition(i -> i > 30);
MutableList greaterThanThirty = partitionedFolks
.getSelected()
.sortThis();
MutableList smallerThanThirty = partitionedFolks
.getRejected()
.sortThis();
Assertions.assertThat(smallerThanThirty)
.containsExactly(1, 5, 8, 17, 23);
Assertions.assertThat(greaterThanThirty)
.containsExactly(31, 38, 41);
}
6.5. Iteração preguiçosa
A iteração lenta é um padrão de otimização no qual um método de iteração é chamado, mas sua execução real é adiada até que seus valores de ação ou retorno sejam exigidos por outro método subsequente.
@Test
public void whenLazyIteration_thenCorrect() {
Student student1 = new Student("John", "Hopkins");
Student student2 = new Student("George", "Adams");
Student student3 = new Student("Jennifer", "Rodriguez");
MutableList students = Lists.mutable
.with(student1, student2, student3);
LazyIterable lazyStudents = students.asLazy();
LazyIterable lastNames = lazyStudents
.collect(Student::getLastName);
Assertions.assertThat(lastNames)
.containsAll(Lists.mutable.with("Hopkins", "Adams", "Rodriguez"));
}
Aqui, o objetolazyStudents não recupera os elementos da listastudents até que o métodocollect() seja chamado.
7. Elementos da coleção de emparelhamento
O métodozip() retorna uma nova coleção combinando elementos de duas coleções em pares. Se alguma das duas coleções for mais longa, os elementos restantes serão truncados.
Vamos ver como podemos usá-lo:
@Test
public void whenZip_thenCorrect() {
MutableList numbers = Lists.mutable
.with("1", "2", "3", "Ignored");
MutableList cars = Lists.mutable
.with("Porsche", "Volvo", "Toyota");
MutableList> pairs = numbers.zip(cars);
Assertions.assertThat(pairs)
.containsExactlyElementsOf(this.expectedPairs);
}
Também podemos emparelhar os elementos de uma coleção com seus índices usando o métodozipWithIndex():
@Test
public void whenZip_thenCorrect() {
MutableList cars = FastList
.newListWith("Porsche", "Volvo", "Toyota");
MutableList> pairs = cars.zipWithIndex();
Assertions.assertThat(pairs)
.containsExactlyElementsOf(this.expectedPairs);
}
8. Conversão de coleções
O Eclipse Collections fornece métodos simples para converter um tipo de contêiner em outro. Esses métodos sãotoList(),toSet(),toBag()etoMap().
Vamos ver como podemos usá-los:
public static List convertToList() {
UnifiedSet cars = new UnifiedSet<>();
cars.add("Toyota");
cars.add("Mercedes");
cars.add("Volkswagen");
return cars.toList();
}
Vamos fazer nosso teste:
@Test
public void whenConvertContainerToAnother_thenCorrect() {
MutableList cars = (MutableList) ConvertContainerToAnother
.convertToList();
Assertions.assertThat(cars)
.containsExactlyElementsOf(
FastList.newListWith("Volkswagen", "Toyota", "Mercedes"));
}
9. Conclusão
Neste tutorial, vimos uma visão geral rápida das Coleções Eclipse e dos recursos que elas fornecem.
A implementação completa deste tutorial está disponívelover on GitHub.