Java Collections Framework
Tags: java, programming, backend, ptbr
Published: 2022-11-22 17:34:51

Uma coleção é um agrupamento de objetos, uma interação de vários objetos em um lugar só. Por exemplo, uma pasta com uma coleção de cartas, uma gaveta com várias chaves etc. Há vários tipos de coleções com diferentes particularidades.

O Java possui uma arquitetura que representa várias coleções: o framework de coleções(Collections Framework). Esse framework nada mais é que a representação de todas as coleções existentes no java, um conjunto que engloba interfaces e classes que representam as estruturas de dados.

Neste post iremos discorrer sobre o uso geral do Collections Framework, para que possamos ter o conhecimento necessário para escolhermos quando usar qual coleção.
 
Toda coleção no java possui:

- Uma interface, que representa uma determinada coleção e nos permite manipulá-la independente de detalhes da implementação(Seguindo o padrão de programar voltado para a interface, não para a implementação).
- As implementações concretas das interfaces, para que possamos implementar de fato uma coleção.
- Métodos para manipularmos as coleções.

Dentro do framework de collections, as interfaces encapsulam várias implementações de coleções, permitindo o acesso a uma coleção sem nos preocuparmos com os detalhes de implementação. 

![Collections Framework](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ll98me3xruqrp3hjte95.png)
 
A coleção principal no java é a interface Collection, e é dela que se originaram as demais interfaces. As principais interfaces do framework estendem diretamente de Collection, elas são o "core" do framework, o ponto principal das coleções.

Cada coleção tem uma particularidade, por isso há várias coleções. Por exemplo, algumas permitem elementos duplicados e outros não, algumas são ordenadas e outras não são ordenadas (Veremos mais à frente quais são algumas dessas características).

Todas as interfaces da coleção principal são genéricas. Por exemplo, esta é uma declaração da Collection:

**public interface Collection< E >**

O uso de “< E >”  nos informa que a interface é genérica, ou seja, aceita qualquer tipo. Portanto, ao declarar uma instância de coleção devemos especificar o tipo de conteúdo do objeto na coleção, por exemplo:

**Collection< Strings > colecao;**

A lista a seguir descreve as principais interfaces e implementações do framework:

<u>**Collection**</u> 
A raiz das coleções, todas as coleções implementam a Collection. Não há nenhuma implementação direta dessa interface, ela é a base de todas as coleções e possui os métodos básicos de toda coleção, como por exemplo: Métodos que informam quantos elementos há na coleção (size, isEmpty),  métodos que verificam se um determinado objeto está na coleção (contains),  métodos que adicionam e removem um elemento da coleção (add, remove) e métodos que fornecem um iterador sobre a coleção (iterador), dentre outros.

Como a Collection é a raiz das coleções, podemos por exemplo “jogar” um Set dentro de um List e vice-versa, e assim usufruirmos dos métodos que precisarmos, pois ambas essas coleções implementam a interface Collection.  

<u>**List**</u>
Uma coleção ordenada e sequencial, que pode conter elementos duplicados. Ela guarda a posição de seus elementos, nos permitindo buscar um elemento dentro de uma List pela sua posição.

As principais implementações de List são: ArrayList, LinkedList e Vector.

- ArrayList: Representa um array com redimensionamento dinâmico(o tamanho vai crescendo conforme são adicionados novos elementos). Possui acesso fácil e performático pelo índice. Os elementos precisam ser copiados para outro array quando não há mais capacidade e, quando uma posição é removida, ela precisa reposicionar as referências. Geralmente é a implementação de melhor desempenho
- LinkedList: Lista duplamente "linkada" (encadeada), que possui uma inserção e remoção performática em qualquer posição, pois nela o elemento B irá guardar qual é o elemento A(anterior a ele) e qual é o elemento C(posterior a ele). Ela também guarda o elemento inicial e o final da lista, e com isso ela não precisa reposicionar as referências quando uma posição é removida (como acontece no Arraylist). O acesso em uma LinkedList é mais demorado pelo índice, pois é preciso ficar pesquisando elemento por elemento (se tem um próximo, se tem um anterior...).
- Vector: Usa um array por baixo dos panos Serve para trabalhos com mais de uma trhead, pois é trhead-safe: enquanto uma pilha usa o recurso, a outra fica esperando para depois usá-lo.

<u>**Set**</u>
É uma coleção usada para representar conjuntos. Um Set não pode conter elementos duplicados, e por isso é mais fácil adicionar e remover elementos, pois não é necessário percorrer todos os objetos ao adicionar/remover/procurar algum deles, como as Lists fazem.
Também não segue uma ordem, é como uma "sacola" cheia de objetos dentro, onde eles estão todos misturados.

A estrutura Set usa uma tabela de espalhamento para realizar mais rapidamente suas buscas. Com isso, ao buscar um objeto, em vez de comparar o objeto com todos os outros objetos contidos dentro do Set ela compara apenas os que possuem o mesmo hashcode. 

Suponha que temos uma Collection e desejamos criar outra Collection contendo os mesmos elementos mas com eliminando os elementos duplicados. Podemos fazer isso convertendo a Collection em alguma implementação de Set, copiando a implementação de Collection para um novo Set ou utilizando um Stream para converter em um Set.

As implementações da interface Set mais utilizadas são: HashSet, LinkedHashSet e TreeSet.

- HashSet: Não guarda ordem, nem mesmo a ordem de inserção dos objetos. Um HashSet armazena seus elementos em uma tabela hash e é a implementação de melhor desempenho.
- LinkedHashSet:  É implementado como uma tabela de hash com uma lista vinculada passando por ela, guardando e ordenando com base na ordem de inserção dos objetos, ou seja, irá trazer os objetos de acordo com a ordem que eles foram inseridos. O LinkedHashSet poupa os usuários da ordem não especificada fornecida por HashSet, com uma leve perda de performance. 
- TreeSet :Armazena os elementos em uma “árvore” os ordenando com base em seus valores, portanto só pode ser utilizado em classes que implementam o Comparable ou passando no construtor do TreeSet como parâmetro um objeto que implementa Comparator, para que assim ele possa fazer ordenações. Também é menos performático se comparado ao HashSet. 

<u>**Queue**</u>
Uma fila usada para armazenar vários elementos antes do seu processamento. As filas normalmente ordenam os elementos de maneira FIFO (primeiro a entrar, primeiro a sair). As filas de prioridade (PriorityQueue) são uma exceção, pois ordenam os elementos de acordo com seus valores.
 
Em uma fila FIFO, todos os novos elementos são inseridos no final da fila. Cada implementação de Queue deve especificar suas propriedades de ordenação. 

É possível que uma Queue implementação restrinja o número de elementos que contém; tais filas são conhecidas como limitadas.

Algumas implementações de Queue são:

- AbstractQueue: A implementação de fila  mais simples possível  que o Java fornece.,  uma implementação básica da interface Queue.
- LinkedList
- PriorityQueu: Uma fila que ordena os elementos de acordo com seus valores.
 
<u>**Deque**</u>
Uma coleção usada para armazenar vários elementos antes do processamento.  É uma fila de duas pontas, onde  todos os novos elementos podem ser inseridos, recuperados e removidos em ambos os extremos.
Deques podem ser usados tanto como uma fila FIFO (primeiro a entrar, primeiro a sair) quanto uma pilha LIFO (último a entrar, primeiro a sair). Em um deque todos os novos elementos podem ser inseridos, recuperados e removidos em ambos os extremos.

Algumas implementações de Deque:

- ArrayDeque: Implementação de uma matriz redimensionável de uma Deque. Crescem conforme são adicionados novos elementos, não são thread-safe e não permitem elementos nulos.
- LinkedList
- ConcurrentLinkedDeque: Fornece suporte à operações simultâneas de inserção, remoção e acesso.

<u>**Map**</u>
Um objeto que mapeia chaves para valores e através da chave podemos acessar o valor correspondente. Map não pode conter chaves duplicadas,  cada chave pode mapear para no máximo um único valor. Se repetimos uma chave, a chave repetida é sobrescrita pela nova.

A plataforma Java contém três Map implementações de uso geral: HashMap, TreeMap e LinkedHashMap. Seu comportamento e desempenho são precisamente análogos a HashSet, TreeSet, e LinkedHashSet.

- HashMap: Implementação baseada em tabela hash da interface Map. Não guarda ordem, nem mesmo a ordem de inserção dos objetos. Um HashMap armazena seus elementos em uma tabela hash e é a implementação de melhor desempenho.
- TreeMap: Uma implementação de Map que armazena os elementos em uma “árvore” os ordenando com base em seus valores, portanto só pode ser utilizado em classes que implementam o Comparable ou passando no construtor do TreeMap como parâmetro um objeto que implementa Comparator, para que assim ele possa fazer ordenações. 
- LinkedHashMap: Tabela de hash e implementação de lista encadeada da interface Map que define a ordem de iteração, que normalmente é a ordem na qual as chaves foram inseridas no mapa(ordem de inserção).

As duas últimas interfaces de coleção principais são apenas versões classificadas de Set e Map:

- SortedSet: Um Set que mantém seus elementos em ordem crescente.

- SortedMap: Um Map que mantém seus mapeamentos em ordem crescente de chaves. Este é o Map análogo de SortedSet.


**FONTE:**

https://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html