Article image
Edson Chaves
Edson Chaves20/10/2025 18:55
Compartilhe

Dominando Collections em Java: De ArrayList a Estruturas Especializadas

  • #Java

Introdução

Collections são o coração de qualquer aplicação Java. Elas permitem armazenar, manipular e recuperar dados de forma eficiente. Mas muitos desenvolvedores limitam-se a ArrayList e HashMap, perdendo oportunidades de usar estruturas especializadas que resolvem problemas de forma elegante.

👉 Código : Acessar o cÓdigo pratico com o uso de collections e suas aplicações -- > CLIQUE AQUI

Neste artigo, exploraremos as Collections mais poderosas e versáteis do Java, com exemplos práticos que você pode aplicar imediatamente em seus projetos.

1. Hierarquia das Collections

Entender a hierarquia é fundamental para escolher a estrutura certa.

Collection
├── List (ordenada, permite duplicatas)
│   ├── ArrayList (busca rápida, inserção lenta)
│   ├── LinkedList (inserção rápida, busca lenta)
│   └── CopyOnWriteArrayList (thread-safe)
├── Set (sem duplicatas)
│   ├── HashSet (não ordenado, rápido)
│   ├── LinkedHashSet (ordem de inserção)
│   └── TreeSet (ordenado, lento)
└── Queue (fila, FIFO)
  ├── PriorityQueue (heap, ordenado por prioridade)
  └── Deque (fila dupla)

Map (chave-valor)
├── HashMap (não ordenado, rápido)
├── LinkedHashMap (ordem de inserção)
├── TreeMap (ordenado por chave)
└── ConcurrentHashMap (thread-safe)

2. List: Quando Usar Cada Uma ArrayList — Acesso Rápido

Use quando você precisa acessar elementos frequentemente.

java

List<String> nomes = new ArrayList<>();
nomes.add("João");
nomes.add("Maria");
nomes.add("Carlos");

// Acesso rápido: O(1)
System.out.println(nomes.get(0)); // "João"

// Inserção no meio é lenta: O(n)
nomes.add(1, "Ana"); // Insere na posição 1

Saída:

João

Complexidade:

  • Acesso: O(1)
  • Inserção: O(n)
  • Remoção: O(n)

LinkedList — Inserção Rápida

Use quando você insere/remove frequentemente no início ou meio.

java

List<String> fila = new LinkedList<>();
fila.add("Primeiro");
fila.add("Segundo");
fila.add("Terceiro");

// Inserção no início: O(1)
fila.addFirst("Zero");

// Remoção do início: O(1)
fila.removeFirst();

// Acesso é mais lento: O(n)
System.out.println(fila.get(1));

Saída:

Segundo

Complexidade:

  • Acesso: O(n)
  • Inserção: O(1)
  • Remoção: O(1)

Comparação Prática

java

// ✅ Use ArrayList para buscas frequentes
List<Integer> numeros = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
for (int i = 0; i < 1000000; i++) {
  numeros.get(i % numeros.size()); // Muito rápido
}

// ✅ Use LinkedList para inserções no início
List<String> historico = new LinkedList<>();
for (int i = 0; i < 10000; i++) {
  historico.addFirst("Evento " + i); // Muito rápido
}

3. Set: Eliminando Duplicatas HashSet — Rápido e Sem Ordem

java

Set<String> emails = new HashSet<>();
emails.add("joao@email.com");
emails.add("maria@email.com");
emails.add("joao@email.com"); // Duplicata ignorada

System.out.println(emails.size()); // 2

// ✅ Perfeito para verificar existência
if (emails.contains("joao@email.com")) {
  System.out.println("Email existe!");
}

Saída:

2
Email existe!

Casos de uso: Cache, verificação de existência, remover duplicatas.

LinkedHashSet — Mantém Ordem

java

Set<String> ordem = new LinkedHashSet<>();
ordem.add("C");
ordem.add("A");
ordem.add("B");

// Itera na ordem de inserção
ordem.forEach(System.out::println); // C, A, B

Saída:

C
A
B

TreeSet — Ordenado Automaticamente

java

Set<Integer> numeros = new TreeSet<>();
numeros.add(5);
numeros.add(1);
numeros.add(3);
numeros.add(2);

// Itera em ordem natural (crescente)
numeros.forEach(System.out::println); // 1, 2, 3, 5

// ✅ Operações de intervalo
NavigableSet<Integer> intervalo = ((TreeSet<Integer>) numeros).subSet(2, true, 4, true);
System.out.println(intervalo); // [2, 3]

Saída:

1
2
3
5
[2, 3]

4. Map: Estrutura Chave-Valor HashMap — Rápido e Flexível

java

Map<String, Integer> salarios = new HashMap<>();
salarios.put("João", 3000);
salarios.put("Maria", 4000);
salarios.put("Carlos", 3500);

// Acesso por chave: O(1)
System.out.println(salarios.get("Maria")); // 4000

// Verificar existência
if (salarios.containsKey("João")) {
  System.out.println("João existe!");
}

// Iterar
salarios.forEach((nome, salario) -> 
  System.out.println(nome + ": R$ " + salario)
);

Saída:

4000
João existe!
Carlos: R$ 3500
João: R$ 3000
Maria: R$ 4000

LinkedHashMap — Mantém Ordem de Inserção

java

Map<String, String> historico = new LinkedHashMap<>();
historico.put("primeiro", "dados");
historico.put("segundo", "dados");
historico.put("terceiro", "dados");

// Itera na ordem de inserção
historico.forEach((chave, valor) -> System.out.println(chave));
// Saída: primeiro, segundo, terceiro

Saída:

primeiro
segundo
terceiro

TreeMap — Ordenado por Chave

java

Map<String, Integer> rankingPalavras = new TreeMap<>();
rankingPalavras.put("zebra", 5);
rankingPalavras.put("apple", 10);
rankingPalavras.put("banana", 7);

// Itera em ordem alfabética
rankingPalavras.forEach((palavra, freq) ->
  System.out.println(palavra + ": " + freq)
);
// Saída: apple, banana, zebra

Saída:

apple: 10
banana: 7
zebra: 5

ConcurrentHashMap — Thread-Safe

Use em aplicações multi-thread:

java

Map<String, Integer> contador = new ConcurrentHashMap<>();

// Seguro para múltiplas threads
new Thread(() -> contador.put("thread1", 1)).start();
new Thread(() -> contador.put("thread2", 2)).start();

5. Queue e Deque: Estruturas Especializadas Queue (FIFO)

java

Queue<String> fila = new LinkedList<>();
fila.add("primeiro");
fila.add("segundo");
fila.add("terceiro");

// Remover do início (FIFO)
System.out.println(fila.poll()); // "primeiro"
System.out.println(fila.poll()); // "segundo"

Saída:

primeiro
segundo

PriorityQueue — Ordenado por Prioridade

java

PriorityQueue<Integer> heap = new PriorityQueue<>();
heap.add(5);
heap.add(1);
heap.add(3);

// Sempre retorna o menor
System.out.println(heap.poll()); // 1
System.out.println(heap.poll()); // 3
System.out.println(heap.poll()); // 5

// Com comparador customizado (maior primeiro)
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
maxHeap.add(5);
maxHeap.add(1);
maxHeap.add(3);
System.out.println(maxHeap.poll()); // 5

Saída:

1
3
5
5

Deque (Fila Dupla)

java

Deque<String> deque = new LinkedList<>();
deque.addFirst("primeiro");
deque.addLast("último");
deque.addFirst("novo primeiro");

System.out.println(deque.removeFirst()); // "novo primeiro"
System.out.println(deque.removeLast());  // "último"

Saída:

novo primeiro
último

6. Exemplo Completo: Sistema de Cache LRU

java

public class CacheLRU<K, V> extends LinkedHashMap<K, V> {
  private int capacidade;
  
  public CacheLRU(int capacidade) {
      // LinkedHashMap com ordem de acesso (LRU)
      super(capacidade, 0.75f, true);
      this.capacidade = capacidade;
  }
  
  @Override
  protected boolean removeEldestEntry(Map.Entry eldest) {
      return size() > capacidade;
  }
  
  public static void main(String[] args) {
      CacheLRU<String, String> cache = new CacheLRU<>(3);
      
      cache.put("página1", "conteúdo1");
      cache.put("página2", "conteúdo2");
      cache.put("página3", "conteúdo3");
      
      System.out.println("Cache após 3 inserts: " + cache.keySet()); 
      // [página1, página2, página3]
      
      cache.get("página1"); // Acesso move para final (LRU)
      cache.put("página4", "conteúdo4"); // Remove página2 (menos recente)
      
      System.out.println("Cache após remover LRU: " + cache.keySet());
      // [página1, página3, página4]
  }
}

Saída:

Cache após 3 inserts: [página1, página2, página3]
Cache após remover LRU: [página1, página3, página4]

7. Conversões Entre Collections

java

// Array para List
String[] array = {"A", "B", "C"};
List<String> lista = Arrays.asList(array);

// List para Array
List<String> lista2 = new ArrayList<>(Arrays.asList("X", "Y", "Z"));
String[] array2 = lista2.toArray(new String[0]);

// Collection para Set (remove duplicatas)
List<Integer> comDuplicatas = Arrays.asList(1, 1, 2, 2, 3);
Set<Integer> semDuplicatas = new HashSet<>(comDuplicatas);

// Unmodifiable Collections
List<String> imutavel = Collections.unmodifiableList(lista);
// imutavel.add("D"); // Lança UnsupportedOperationException

Mostrar Imagem

8. Performance: Escolhendo a Estrutura Certa

OperaçãoArrayListLinkedListHashSetTreeSetHashMapAcessoO(1) ✅O(n)——O(1) ✅Inserção (início)O(n)O(1) ✅———Inserção (fim)O(1) ✅O(1) ✅O(1) ✅O(log n)O(1) ✅RemoçãoO(n)O(n)O(1) ✅O(log n)O(1) ✅BuscaO(n)O(n)O(1) ✅O(log n)O(1) ✅Ordenado❌❌❌✅❌

Mostrar Imagem

Regra de Ouro: Escolha a estrutura baseado em suas operações mais frequentes.

9. Referências

Conclusão

Collections não são um detalhe técnico — são o alicerce de aplicações eficientes. Conhecer as diferenças entre ArrayList e LinkedList, entre HashSet e TreeSet, entre HashMap e ConcurrentHashMap faz toda a diferença quando você precisa escalar suas aplicações.

Use a estrutura certa para o trabalho certo, e suas aplicações Java rodarão com performance e elegância.

Chamada para Ação

👉 Código : Acessar o cÓdigo pratico com o uso de collections e suas aplicações -- > CLIQUE AQUI

👉 Desafio: Identifique Collections em seu código atual e verifique se são as mais eficientes para seus casos de uso. Refatore e meça a melhoria de performance!

📌 Próximo nível: Explore Generics avançados e Collections com padrões de design.

#Java #Collections #Performance #CleanCode #DIO

Compartilhe
Comentários (0)