Pular para conteúdo

Coleções e Tipos Genéricos

O Java Collections Framework separa interfaces como List, Set, Queue e Map de implementações com diferentes propriedades de desempenho e ordenação.

Programar para o contrato necessário

static List<String> normalizedNames(Collection<String> names) {
    List<String> result = new ArrayList<>(names.size());
    for (String name : names) {
        result.add(name.strip().toLowerCase(Locale.ROOT));
    }
    return List.copyOf(result);
}

O parâmetro requer apenas iteração e tamanho, enquanto o contrato de retorno é uma lista imutável. "Imutável" não torna elementos mutáveis referenciados profundamente imutáveis.

Tipos genéricos

Tipos genéricos fornecem segurança de tipos em tempo de compilação. Os tipos genéricos de Java são invariantes: List<Integer> não é um subtipo de List<Number>. Wildcards expressam variação em um limite de API.

static double sum(List<? extends Number> values) {
    double total = 0;
    for (Number value : values) total += value.doubleValue();
    return total;
}

static void addDefaults(List<? super Integer> destination) {
    destination.add(0);
    destination.add(1);
}

O mnemônico PECS significa produtor-extends, consumidor-super. Um valor lido de ? super Integer é apenas conhecido como Object; um Number arbitrário não-nulo não pode ser adicionado com segurança a ? extends Number.

Guia de seleção

Necessidade Implementação típica
Sequência indexada ArrayList
Valores únicos, sem requisito de ordem de iteração HashSet
Conjunto/mapa ordenado por inserção LinkedHashSet / LinkedHashMap
Chaves ordenadas TreeSet / TreeMap
Pilha ou fila ArrayDeque
Acesso de prioridade PriorityQueue

Erros comuns

  • modificar uma coleção durante um laço for-each fora do contrato do iterador;
  • usar objetos mutáveis como chaves hash;
  • presumir ordem de iteração de HashMap;
  • retornar diretamente uma coleção interna mutável;
  • selecionar uma coleção concorrente sem entender suas operações atômicas.