Interface List e suas Implementações
A interface List é uma subinterface de Collection projetada para manter uma sequência ordenada de elementos. Diferente de outras coleções, ela preserva a ordem de inserção, permite duplicatas e fornece acesso direto via índice. As principais implementações são ArrayList, LinkedList e Vector.
ArrayList: Baseado em Vetores Dinâmicos
O ArrayList utiliza uma estrutura de array internamente. Isso garante consultas rápidas por índice, mas torna a inserção e remoção no meio da estrutura mais custosa. Ele não é thread-safe, o que resulta em maior desempenho em ambientes de thread única.
- O array inicial é alocado apenas na primeira adição de elemento, não no momento da instanciação.
- Quando a capacidade máxima é atingida, o array é redimensionado automaticamente usando
Arrays.copyOf(). - O fator de expansão padrão é de 1,5 vezes o tamanho atual.
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class GerenciadorSequencial {
public static void main(String[] args) {
List<string> repositorio = new ArrayList<>();
repositorio.add("TecnologiaA");
repositorio.add("TecnologiaB");
repositorio.add("TecnologiaC");
repositorio.add("TecnologiaB"); // Permite duplicatas
System.out.println("Conteúdo inicial: " + repositorio);
// Inserção em índice específico
repositorio.add(2, "TecnologiaD");
System.out.println("Após inserção no índice 2: " + repositorio);
// Recuperação e substituição
String elementoResgatado = repositorio.get(1);
System.out.println("Elemento no índice 1: " + elementoResgatado);
repositorio.set(1, "TecnologiaAtualizada");
System.out.println("Após substituição: " + repositorio);
// Iteração bidirecional
ListIterator<string> iteradorSeq = repositorio.listIterator();
while (iteradorSeq.hasNext()) {
System.out.print(iteradorSeq.next() + " ");
}
System.out.println("\n--- Ordem inversa ---");
while (iteradorSeq.hasPrevious()) {
System.out.print(iteradorSeq.previous() + " ");
}
}
}</string></string>
LinkedList: Lista Duplamente Encadeada
A LinkedList utiliza nós conectados entre si, permitindo adições e remoções eficientes nas extremidades. Embora possua métodos de acesso por índice, a navegação sequencial é mais performática. Oferece métodos dedicados para operações de pilha (stack) e fila (queue).
import java.util.LinkedList;
public class OperacoesListaEncadeada {
public static void main(String[] args) {
LinkedList<string> filaProcessos = new LinkedList<>();
filaProcessos.add("ProcessoX");
filaProcessos.add("ProcessoY");
filaProcessos.add("ProcessoZ");
// Operações nas extremidades
filaProcessos.addFirst("ProcessoInicio");
filaProcessos.addLast("ProcessoFim");
System.out.println("Primeiro: " + filaProcessos.peekFirst());
System.out.println("Último: " + filaProcessos.peekLast());
System.out.println("Removendo primeiro: " + filaProcessos.removeFirst());
System.out.println("Removendo último: " + filaProcessos.removeLast());
System.out.println("Estado final: " + filaProcessos);
}
}</string>
Simulando uma Pilha com LinkedList
Abaixo, uma implementação encapsulada que expõe comportamento LIFO (Last In, First Out):
import java.util.LinkedList;
public class PilhaGenerica {
private LinkedList<object> armazenamento;
public PilhaGenerica() {
armazenamento = new LinkedList<>();
}
public void empilhar(Object item) {
armazenamento.addFirst(item);
}
public Object desempilhar() {
if (armazenamento.isEmpty()) {
throw new IllegalStateException("A pilha está vazia.");
}
return armazenamento.removeFirst();
}
public int capacidadeAtual() {
return armazenamento.size();
}
@Override
public String toString() {
return "Pilha[conteudo=" + armazenamento + "]";
}
}</object>
Vector: Legado Sincronizado
O Vector funciona de maneira similar ao ArrayList, mas suas operações são protegidas por synchronized. Devido à sobrecarga de thread safety, é desencorajado em aplicações modernas, sendo substituído por Collections.synchronizedList() ou CopyOnWriteArrayList.
Interface Set: Elementos Únicos
A interface Set proíbe duplicatas e não garante ordem de iteração (exceto implementações específicas). As principais variações são HashSet e TreeSet.
HashSet: Desempenho com Tabela Hash
Baseado no HashMap, o HashSet oferece operações de adição, remoção e busca em tempo constante médio O(1). A verificação de unicidade depende dos contratos de hashCode() e equals().
import java.util.HashSet;
import java.util.Objects;
public class RegistroUsuarios {
public static void main(String[] args) {
HashSet<string> nomesUnicos = new HashSet<>();
nomesUnicos.add("Ana");
nomesUnicos.add("Bruno");
nomesUnicos.add("Ana"); // Ignorado automaticamente
System.out.println("Usuários registrados: " + nomesUnicos);
}
}
// Classe de apoio para demonstrar hash/equals customizados
class Aluno {
private String matricula;
private int anoLetivo;
public Aluno(String matricula, int anoLetivo) {
this.matricula = matricula;
this.anoLetivo = anoLetivo;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Aluno)) return false;
Aluno outro = (Aluno) o;
return anoLetivo == outro.anoLetivo && matricula.equals(outro.matricula);
}
@Override
public int hashCode() {
return Objects.hash(matricula, anoLetivo);
}
}</string>
TreeSet: Ordenação Automática
Utiliza uma árvore rubro-negra internamente. Garante unicidade e mantém os elementos ordenados. Suporta ordenação natural (Comparable) ou personalizada (Comparator).
import java.util.Comparator;
import java.util.TreeSet;
public class CatalogoProdutos {
public static void main(String[] args) {
// Ordenação natural de strings
TreeSet<string> frutas = new TreeSet<>();
frutas.add("Maçã");
frutas.add("Uva");
frutas.add("Banana");
System.out.println(frutas);
// Ordenação customizada via Comparator: preço crescente, depois nome
TreeSet<produto> estoque = new TreeSet<>((p1, p2) -> {
int cmp = Integer.compare(p1.preco, p2.preco);
return (cmp != 0) ? cmp : p1.nome.compareTo(p2.nome);
});
estoque.add(new Produto("Notebook", 3000));
estoque.add(new Produto("Mouse", 50));
estoque.add(new Produto("Teclado", 150));
estoque.add(new Produto("Mouse", 50)); // Duplicata ignorada
System.out.println("Estoque ordenado: " + estoque);
}
}
class Produto {
String nome;
int preco;
Produto(String n, int p) { nome = n; preco = p; }
public String toString() { return nome + " (R$" + preco + ")"; }
}</produto></string>
Interface Map: Mapeamento Chave-Valor
A interface Map armazena pares chave-valor, onde cada chave deve ser única. Não é uma subinterface de Collection. Pricnipais implementações: HashMap, TreeMap, LinkedHashMap e Hashtable.
HashMap vs Hashtable
- HashMap: Não sincronizado, permite chaves e valores
null, maior desempenho. - Hashtable: Sincronizado, proíbe
null, legado. Substitua porConcurrentHashMapem cenários concorrentes.
import java.util.HashMap;
import java.util.Map;
public class ComparacaoMapas {
public static void main(String[] args) {
HashMap<string string=""> mapModerno = new HashMap<>();
mapModerno.put(null, "valor_nulo");
mapModerno.put("chave_valida", null);
mapModerno.put(null, null);
System.out.println("HashMap aceita nulos: " + mapModerno);
// Hashtable lançaria NullPointerException nas operações acima
// Hashtable<string string=""> tableLegado = new Hashtable<>();
}
}</string></string>
Contagem de Frequência de Caracteres
Exemplo prático de uso de Map para analisar dados textuais:
import java.util.Map;
import java.util.TreeMap;
public class AnaliseFrequencia {
public static void main(String[] args) {
String textoEntrada = "aababcabcdabcde";
Map<character integer=""> contador = new TreeMap<>();
textoEntrada.chars().mapToObj(c -> (char) c)
.forEach(c -> contador.merge(c, 1, Integer::sum));
StringBuilder resultado = new StringBuilder();
contador.forEach((k, v) -> resultado.append(k).append("(").append(v).append(")"));
System.out.println(resultado.toString());
}
}</character>
LinkedHashMap: Preservação de Ordem de Inserção
Combina a performance de hash com uma lista encadeada que registra a ordem de adição. Útil para caches LRU ou quando a sequência importa.
import java.util.LinkedHashMap;
import java.util.Map;
public class ConfiguracoesSistema {
public static void main(String[] args) {
LinkedHashMap<string string=""> props = new LinkedHashMap<>();
props.put("DB_HOST", "localhost");
props.put("DB_PORT", "5432");
props.put("CACHE_TTL", "3600");
props.put("LOG_LEVEL", "DEBUG");
props.forEach((k, v) -> System.out.println(k + " = " + v));
}
}</string>
Utilitário Collections
A classe Collections fornece métodos estáticos para manipulação segura e eficiente de coleções. Um uso comum é a proteção de coleções padrão para ambientes multithread:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ColecaoThreadSafe {
public static void main(String[] args) {
List<string> listaBase = new ArrayList<>();
listaBase.add("ItemA");
listaBase.add("ItemB");
// Envolve a lista não segura em uma wrapper sincronizada
List<string> listaProtegida = Collections.synchronizedList(listaBase);
System.out.println("Lista segura: " + listaProtegida);
}
}</string></string>