HashMaps e coleções em Java

Aprenda a armazenar e consultar dados por chave com HashMap, contar e agrupar valores e manter valores únicos com HashSet. Conheça as garantias das interfaces List, Set e Map, ordene listas, defina uma ordem natural para suas próprias classes com Comparable e escolha a coleção adequada para cada tarefa.

BásicoAula 7 de 11 do curso Curso de Programação orientada a objetos com Java

O que você vai aprender

  1. Crie mapas de dispersão, adicione, leia, atualize e remova pares chave–valor, percorra o conteúdo de um mapa e use suas próprias classes como chaves que o mapa possa encontrar novamente.
    • Crie um HashMap e insira, consulte, atualize e remova entradas
      Declare um HashMap com seus tipos de chave e de valor, armazene pares com put, leia-os com get e trate chaves ausentes.
    • Percorra chaves, valores e entradas
      Percorra todos os pares de um mapa com keySet, values e entrySet, saiba qual ordem esperar e altere um mapa com segurança durante o percurso.
    • Use seus próprios objetos como chaves de mapas
      Faça objetos de suas próprias classes funcionarem como chaves, sobrescrevendo equals e hashCode em conjunto, e mantenha as chaves inalteradas enquanto estiverem em um mapa.
  2. Use mapas para contar a frequência de ocorrências, reunir valores relacionados sob uma mesma chave e construir tabelas de consulta que encontrem objetos rapidamente.
    • Conte ocorrências e acumule totais por chave
      Construa tabelas de frequências e somas acumuladas com o padrão getOrDefault e interprete os resultados corretamente.
    • Agrupe valores sob uma mesma chave usando listas e conjuntos como valores
      Construa mapas cujos valores sejam listas ou conjuntos, adicione itens ao grupo correto e evite erros que façam grupos se perderem ou deixarem de funcionar.
    • Consulte objetos e preços rapidamente com um índice baseado em mapa
      Use mapas como tabelas de consulta e índices que encontram objetos por uma chave única, mantenha-os dentro de uma classe e mantenha vários índices consistentes.
  3. Use HashSet para armazenar valores sem duplicatas, testar a pertinência rapidamente e combinar conjuntos por união, interseção e diferença.
    • Armazene valores únicos e teste a pertinência com HashSet
      Adicione, verifique e remova valores em um HashSet, use o resultado de add e remova duplicatas de uma lista.
    • Combine conjuntos e mantenha sua ordem
      Calcule uniões, interseções e diferenças sem alterar os conjuntos originais, compare conjuntos e escolha um conjunto ordenado quando a ordem importar.
  4. Declare coleções por seus tipos de interface, conheça as garantias de cada interface e use os métodos comuns que funcionam nas diferentes implementações.
    • Declare variáveis e parâmetros com tipos de interface
      Explique o que é um tipo de interface, declare coleções como List, Set ou Map e escreva métodos que aceitem qualquer implementação.
    • Conheça as garantias de List, Set e Map
      Compare as garantias das três interfaces, reconheça suas principais implementações e trabalhe com coleções não modificáveis criadas com of.
  5. Ordene listas em ordem natural, defina uma ordem natural para suas próprias classes implementando Comparable e use essa ordem em conjuntos e mapas ordenados.
    • Ordene listas de números e cadeias de caracteres
      Ordene uma lista na própria lista com Collections.sort, preveja a ordem de cadeias de caracteres e ordene em ordem inversa ou sem distinguir maiúsculas de minúsculas.
    • Implemente Comparable em sua própria classe
      Defina uma ordem natural para uma classe implementando Comparable e escrevendo compareTo com comparações seguras de números e cadeias de caracteres.
    • Resolva empates e use conjuntos e mapas ordenados
      Ordene objetos por vários campos, mantenha compareTo consistente com equals e use TreeSet e TreeMap para manter dados ordenados.
  6. Compare a velocidade das operações comuns em cada coleção e escolha o tipo adequado ao que o programa precisa fazer com seus dados.
    • Compare o custo de operações comuns em coleções
      Estime como o tempo de consultas, inserções e remoções cresce com o tamanho de cada coleção e identifique padrões lentos.
    • Selecione uma coleção que atenda à tarefa
      Responda a algumas perguntas sobre ordem, duplicatas e consultas para escolher entre vetores, listas, conjuntos e mapas, e combine-os para dados mais complexos.

Guia de estudo de HashMaps e coleções em Java

6 capítulos

1

Armazene e consulte dados por chave com HashMap

Um código de produto pode levar diretamente a uma quantidade em estoque, sem pesquisar uma lista. Mapas tornam essa associação explícita, mas usá-los bem também exige tratar chaves ausentes, visitar pares com segurança e definir quando dois objetos usados como chaves são considerados iguais. Comece com um pequeno mapa de estoque e acompanhe como seu conteúdo muda e como Java encontra novamente uma chave armazenada. As mesmas regras de igualdade serão importantes quando você usar conjuntos.

1.1 Crie um HashMap e insira, consulte, atualize e remova entradas

Um mapa armazena uma associação de cada chave a um valor. Em um mapa de estoque, o nome de um produto é a chave e sua quantidade é o valor. Dois produtos podem ter a mesma quantidade, mas uma chave de produto não pode ter duas entradas separadas.

Crie o mapa
import java.util.HashMap;

HashMap<String, Integer> stock = new HashMap<>();

O primeiro tipo, String, descreve as chaves. O segundo, Integer, descreve os valores. O diamante <> à direita permite que Java infira esses tipos. Os argumentos de tipo devem ser tipos de referência: use Integer, Double, Character ou Boolean em vez de int, double, char ou boolean. Java empacota um int simples quando o armazena como Integer e desempacota um Integer quando um int é necessário.

Acompanhe cada alteração
stock.put("apple", 12);
stock.put("pear", 7);
Integer previous = stock.put("apple", 15);

A primeira chamada cria apple=12; a segunda adiciona pear=7. A terceira encontra a chave existente "apple" e substitui seu valor. O mapa agora tem duas entradas, e previous contém 12. Um put para uma chave sem associação anterior retorna null.

stock.get("apple") agora retorna 15. stock.remove("pear") retorna 7 e remove essa entrada. Remover "pear" novamente retorna null. size() conta as entradas, isEmpty() verifica se não há nenhuma e clear() remove todas as entradas.

Trate uma chave ausente

stock.get("kiwi") retorna null, e stock.containsKey("kiwi") retorna false. Esta instrução compila, mas falha quando é executada:

int quantity = stock.get("kiwi");

Java tenta desempacotar null em um int, causando uma NullPointerException. Para um mapa de quantidades não nulas, use um valor padrão:

int quantity = stock.getOrDefault("kiwi", 0);

Isso fornece 0 sem adicionar "kiwi" ao mapa. Você também pode verificar containsKey antes da leitura. containsValue(15) verifica se alguma entrada tem esse valor; ele pode percorrer todos os valores, portanto é diferente de encontrar uma chave conhecida.

Um HashMap também permite uma chave null e valores null. Se uma chave estiver explicitamente associada a null, getOrDefault retornará o null armazenado, não o valor padrão. containsKey distingue esse caso de uma chave ausente. Mapas de quantidades são mais simples quando cada quantidade armazenada é um número real.

Faça a correspondência correta de chaves e valores

Chaves do tipo String distinguem maiúsculas de minúsculas: "apple", "Apple" e "apple " são diferentes. Aplique a mesma limpeza antes de armazenar e pesquisar, por exemplo, name.trim().toLowerCase(). Limpar apenas uma chave de pesquisa não corrige chaves armazenadas de forma inconsistente.

Compare valores empacotados pelo conteúdo com equals. Se duas entradas contiverem 1000, suas referências Integer podem ser diferentes, portanto == pode ser falso mesmo que seus conteúdos numéricos correspondam. Depois de verificar que ambos os valores são não nulos, a.equals(b) compara seus conteúdos.

Principais conclusões

  • Cada chave única está associada a um valor; valores podem se repetir.
  • put substitui um valor existente e retorna o valor anterior.
  • Uma chamada a get para uma chave ausente retorna null; desempacotá-lo causa uma NullPointerException.
  • getOrDefault fornece um valor padrão somente para uma chave ausente.
  • Faça a correspondência de chaves de texto de forma consistente e compare valores empacotados pelo conteúdo.

1.2 Percorra chaves, valores e entradas

Um mapa pode responder a uma única consulta ou fornecer todos os seus dados a um laço. Escolha a visão que fornece as partes necessárias ao laço. As visões estão vinculadas ao mapa, portanto alterações feitas por meio delas também podem alterar o mapa.

Escolha chaves, valores ou entradas

Use keySet() para visitar as chaves. Uma consulta dentro desse laço pode recuperar cada valor:

for (String name : phoneBook.keySet()) {
    System.out.println(name + ": " + phoneBook.get(name));
}

Use values() quando as chaves não forem relevantes. Para as quantidades em estoque maçã 15, pera 7 e figo 3:

int total = 0;
for (int quantity : stock.values()) {
    total += quantity;
}

O total passa a ser 25. Valores repetidos ainda contribuem separadamente: uma visão de valores não é um conjunto.

Uma entrada contém uma chave e seu valor juntos. Importe java.util.Map e use Map.Entry<K, V> com getKey() e getValue(). Isso evita uma segunda consulta:

String best = null;
int bestScore = Integer.MIN_VALUE;
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    if (best == null || entry.getValue() > bestScore) {
        best = entry.getKey();
        bestScore = entry.getValue();
    }
}

Para Ana 82, Ben 91 e Cai 77, o resultado é Ben com 91. O teste best == null também trata uma primeira pontuação igual ao menor valor possível de int. Um mapa vazio deixa best como null.

Escolha a ordem explicitamente

Um HashMap não garante uma ordem de iteração. Não se pode presumir a ordem de inserção, a ordem classificada ou a ordem exibida hoje. Um LinkedHashMap preserva a ordem de inserção; um TreeMap visita as chaves em ordem classificada. Se duas pontuações empatarem, o laço anterior mantém a primeira visitada. Com um HashMap, qualquer um dos nomes empatados pode vencer. Adicione uma regra explícita de desempate quando o resultado precisar ser previsível.

Remova entradas pelo iterador

Chamar stock.remove(key) dentro de um laço for-each que percorre stock.keySet() altera as chaves usadas pelo laço. Isso pode causar uma ConcurrentModificationException. A detecção não é garantida; uma execução sem exceção não torna esse padrão válido.

Use o próprio método de remoção do iterador:

Iterator<Map.Entry<String, Integer>> it =
    stock.entrySet().iterator();
while (it.hasNext()) {
    if (it.next().getValue() == 0) {
        it.remove();
    }
}

Importe java.util.Iterator. Para maçã 15, pera 0, figo 0 e kiwi 4, isso remove pera e figo. Outra abordagem segura registra as chaves em uma lista, termina o laço e depois as remove.

Substituir um valor existente não adiciona nem remove uma chave. Durante um laço sobre entradas, entry.setValue(entry.getValue() * 2) pode dobrar as quantidades com segurança. Não adicione novas chaves por meio do mapa durante esse laço.

Distinga uma visão de uma cópia

stock.keySet().remove("apple") remove a entrada correspondente do mapa. Uma lista separada criada com new ArrayList<>(stock.keySet()) é uma cópia das chaves atuais. Ordenar essa lista não reordena o mapa, e remover um nome da lista não remove sua associação no mapa.

Principais conclusões

  • Use keySet, values ou entrySet conforme as necessidades do laço.
  • HashMap não tem ordem de iteração garantida; resolva empates explicitamente.
  • Use o remove de um iterador para excluir durante o percurso.
  • Substituir um valor existente é permitido durante o percurso.
  • As visões de um mapa estão vinculadas a ele; uma lista de chaves copiada é separada.

1.3 Use seus próprios objetos como chaves de mapas

Um ID de produto armazenado como String já tem regras de igualdade úteis. Uma chave criada a partir de sua própria classe exige uma decisão: dois objetos separados com os mesmos dados representam a mesma chave?

Códigos de dispersão limitam a busca; a igualdade a confirma

Um HashMap usa hashCode() para ajudar a localizar uma chave e equals() para verificar uma correspondência. Chaves iguais devem ter códigos de dispersão iguais. Chaves diferentes podem compartilhar um código de dispersão; a igualdade ainda as distingue. Classes padrão de valores, como String e Integer, já seguem esse contrato.

Sem sobrescritas, uma classe herda de Object a igualdade baseada em identidade. Dois pontos criados separadamente com coordenadas 2 e 3 são chaves diferentes, embora seus campos correspondam:

labels.put(new Point(2, 3), "door");
String label = labels.get(new Point(2, 3));

Com igualdade por identidade, label é null. A consulta criou um segundo objeto, diferente daquele usado na inserção.

Sobrescreva os dois métodos em conjunto

Aqui as coordenadas de um ponto definem seu conteúdo:

import java.util.Objects;

final class Point {
    private final int x;
    private final int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof Point)) {
            return false;
        }
        Point point = (Point) other;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

A verificação de identidade trata rapidamente o caso do mesmo objeto. A verificação de tipo rejeita null e objetos de tipos não relacionados. A comparação final verifica as duas coordenadas. Objects.hash(x, y) constrói o código de dispersão a partir desses mesmos campos. Com essa classe, a consulta anterior retorna "door".

Sobrescrever apenas equals mantém o cálculo de hash herdado, que não garante códigos de dispersão iguais para objetos separados com campos iguais. Um mapa pode então deixar de encontrar uma chave igual. Um código de dispersão constante preservaria a correção, mas tornaria a busca lenta. Gerar as duas sobrescritas em um editor ajuda a evitar o uso de campos incompatíveis.

Use a assinatura exata do método

public boolean equals(Point other) faz uma sobrecarga do método; não substitui equals(Object). A consulta no mapa usa equals(Object), portanto a nova sobrecarga não fornece ao mapa igualdade por conteúdo. A anotação @Override faz uma assinatura errada gerar um erro de compilação em vez de um defeito oculto na consulta.

Mantenha estável a identidade da chave

Não altere campos que determinam a igualdade ou o código de dispersão de uma chave enquanto ela estiver armazenada. Se um ponto armazenado mudar de (2, 3) para (5, 3), o mapa pode deixar de encontrá-lo por qualquer um dos valores, embora size() permaneça igual. Remova-o antes de alterá-lo e depois insira-o novamente. Tornar os campos da chave final, como acima, evita esse erro.

Essas regras também determinam a pertinência em um HashSet. Um ArrayList usa equals para buscas por conteúdo, como contains; não precisa de códigos de dispersão para essa busca.

Principais conclusões

  • Objetos iguais devem ter códigos de dispersão iguais; objetos diferentes podem compartilhar um código.
  • Sobrescreva equals(Object) e hashCode() com campos correspondentes.
  • @Override detecta uma sobrecarga acidental de equals.
  • Mantenha inalterados os campos que definem a igualdade e o código de dispersão enquanto uma chave estiver armazenada.
2

Conte, agrupe e indexe dados com mapas

Um mapa pode construir informações úteis enquanto um programa lê dados: uma contagem para cada palavra, uma lista para cada curso ou um objeto para cada ID. A escolha importante é o que cada valor representa. Um número acumula um resultado; uma lista ou um conjunto reúne um grupo; uma referência a objeto forma um índice. Acompanhe cada atualização a partir de um mapa vazio para que as primeiras ocorrências, as chaves repetidas e os objetos compartilhados tenham comportamentos claros.

2.1 Conte ocorrências e acumule totais por chave

Uma tabela de frequências tem uma chave para cada item distinto e um número que indica quantas vezes ele ocorre. A primeira ocorrência inicia uma contagem; cada ocorrência posterior atualiza essa mesma entrada.

Construa uma contagem, um item de cada vez
HashMap<String, Integer> counts = new HashMap<>();
for (String word : text.split(" ")) {
    int oldCount = counts.getOrDefault(word, 0);
    counts.put(word, oldCount + 1);
}

Para o texto “o gato viu o cão e o gato correu”, a primeira ocorrência de “o”, correspondente a "the" no texto original, ainda não está no mapa, portanto sua contagem anterior é 0 e a nova é 1. Suas duas ocorrências seguintes alteram essa entrada para 2 e depois para 3. A contagem de “gato”, correspondente a "cat", termina em 2; as contagens de “viu”, “cão”, “e” e “correu”, correspondentes a "saw", "dog", "and" e "ran", terminam em 1 cada.

Há 6 palavras distintas, portanto counts.size() é 6. A soma dos valores é 9, o número de ocorrências de palavras. Eles medem coisas diferentes: o tamanho do mapa não é o comprimento da sequência original.

A atualização pode ser escrita em uma linha:

counts.put(word, counts.getOrDefault(word, 0) + 1);

Uma forma equivalente mais longa verifica containsKey, incrementa uma contagem existente e armazena 1 para uma nova chave. Todas as contagens armazenadas nesse padrão são não nulas.

Preserve o resultado anterior

Chamar counts.put(word, 1) para cada palavra sobrescreve repetidamente cada contagem com 1. Isso registra que uma palavra existe, mas perde sua frequência. Chamar counts.get(word) + 1 sem tratar a primeira ocorrência tenta desempacotar null e falha. O valor padrão deve estar na etapa de leitura; a contagem aumentada deve então ser armazenada novamente.

Decida o que conta como o mesmo item

A igualdade de cadeias de caracteres é exata. "The" e "the" são chaves diferentes, assim como "cat" e "cat,". Se a tarefa as tratar como a mesma palavra, limpe cada unidade de entrada antes de contá-la. Converta o texto para minúsculas e remova a pontuação que o programa trata como separadores. Use uma regra consistente para que os resultados não dependam de qual grafia apareceu primeiro.

A chave também pode ser um caractere. Com HashMap<Character, Integer>, um laço sobre "banana".toCharArray() produz a=3, n=2 e b=1 usando o mesmo padrão de ler, aumentar e armazenar.

Acumule quantias em vez de ocorrências

Para totais por categoria, adicione a quantia atual em vez de 1:

HashMap<String, Double> totals = new HashMap<>();
double oldTotal = totals.getOrDefault(category, 0.0);
totals.put(category, oldTotal + amount);

Alimentação 12,50, transporte 3,20 e alimentação 7,25 resultam em alimentação 19,75 e transporte 3,20. O valor padrão é 0.0, correspondente ao tipo de valor Double. O mapa continua tendo uma entrada por categoria, independentemente de quantas quantias contribuíram para ela.

Interprete a tabela concluída

Percorra as entradas para encontrar a maior contagem ou o maior total, guardando a melhor chave e seu valor. Especifique uma regra de desempate, se necessário. Para um relatório em ordem alfabética, new TreeMap<>(counts) copia as associações em ordem classificada de chaves. Os valores das contagens permanecem inalterados; ordenar as chaves não ordena as categorias por seus totais.

Principais conclusões

  • Um mapa de frequências armazena uma contagem por chave distinta.
  • Leia a contagem anterior com zero como valor padrão, adicione um e armazene o resultado.
  • O tamanho do mapa conta itens distintos; a soma das contagens mede as ocorrências.
  • Normalize o texto de forma consistente antes de contar.
  • Use o mesmo padrão de atualização para somar quantias por chave.
  • Escolha a ordem do relatório separadamente dos valores acumulados.

2.2 Agrupe valores sob uma mesma chave usando listas e conjuntos como valores

Um valor de mapa pode ser uma coleção. Quando vários alunos pertencem a um curso, o curso é uma chave e a lista associada contém todos os seus alunos. A regra de chave única do mapa continua válida: a lista é o único valor daquele curso.

Crie um grupo antes de adicionar itens a ele
HashMap<Character, ArrayList<String>> groups = new HashMap<>();
for (String fruit : fruits) {
    char letter = fruit.charAt(0);
    if (!groups.containsKey(letter)) {
        groups.put(letter, new ArrayList<>());
    }
    groups.get(letter).add(fruit);
}

Para “apple”, “banana”, “avocado”, “cherry” e “blueberry”, a primeira fruta cria a lista de a e adiciona “apple”. “Banana” cria a lista de b. “Avocado” encontra a lista existente de a e é adicionado a ela. O resultado é a → [apple, avocado], b → [banana, blueberry] e c → [cherry]. Cada lista mantém sua própria ordem de inserção, embora o HashMap não ordene suas chaves.

A verificação pode ser abreviada:

groups.putIfAbsent(letter, new ArrayList<>());
groups.get(letter).add(fruit);

putIfAbsent mantém uma lista existente não nula. O get seguinte retorna essa lista, pronta para receber o item.

Mantenha a lista que você já construiu

Um groups.put(letter, new ArrayList<>()) incondicional dentro do laço substitui a lista anterior a cada ocorrência. Apenas a última fruta de cada letra permanece depois do add seguinte. O erro oposto é deixar de criar a lista: groups.get(letter).add(fruit) lança uma NullPointerException para uma nova chave porque ainda não existe uma lista.

Entenda a referência

get retorna a referência à lista armazenada. Adicionar um item a ela altera essa mesma lista, portanto não é necessário inseri-la novamente. Isso também explica um erro de compartilhamento:

ArrayList<String> shared = new ArrayList<>();
courses.put("Art", shared);
courses.put("Music", shared);
courses.get("Art").add("Jin");

Agora ambas as chaves levam a [Jin]. Duas chaves não criaram duas listas. Crie uma nova lista para cada novo grupo quando os grupos precisarem ser independentes.

Escolha listas ou conjuntos dentro dos grupos

Uma lista preserva adições repetidas. Um conjunto impede duplicatas dentro do grupo. Um HashMap<String, HashSet<String>> pode, portanto, reunir as matrículas distintas dos alunos sem contar o mesmo aluno duas vezes em um curso. A regra do conjunto se aplica dentro de cada valor; o mapa externo continua tendo uma entrada por curso.

Para ler um grupo que pode estar ausente, verifique containsKey ou use groups.getOrDefault(letter, new ArrayList<>()). Uma chave ausente então produz uma lista vazia para essa chamada. A lista padrão não é inserida automaticamente; adicionar um item a ela não cria um grupo armazenado.

Remover o último item de um grupo deixa a chave associada a uma coleção vazia. Se o programa não deve mais listar grupos vazios, verifique isEmpty() e remova também essa chave. Conte os grupos pelo tamanho do mapa externo e os itens pelos tamanhos das coleções internas.

Principais conclusões

  • Garanta que um grupo exista e depois adicione itens à sua lista ou ao seu conjunto armazenado.
  • Crie uma nova coleção para cada grupo independente.
  • get retorna a referência armazenada, portanto alterações internas não precisam de outro put.
  • Valores do tipo lista mantêm repetições; valores do tipo conjunto mantêm membros distintos em cada grupo.
  • Um grupo vazio armazenado ainda tem uma entrada no mapa.

2.3 Consulte objetos e preços rapidamente com um índice baseado em mapa

Um índice associa uma chave de identificação a um objeto. Uma biblioteca pode encontrar um livro pelo ISBN sem percorrer todos os livros de uma lista. Uma tabela de consulta usa a mesma estrutura para associar um código a um valor simples, como o preço de um produto.

Escolha uma chave de identificação

Um HashMap<String, Book> pode associar um ISBN ao seu livro. Cada consulta precisa apenas da chave. O nome de uma pessoa muitas vezes é uma chave única inadequada: armazenar outra pessoa chamada “Sam Lee” sob essa mesma cadeia de caracteres substitui a pessoa anterior. Use um ID único ou um mapa de agrupamento se um nome deve levar a várias pessoas.

Mantenha um índice dentro da classe responsável pelos dados:

class Library {
    private HashMap<String, Book> byIsbn;

    Library() {
        byIsbn = new HashMap<>();
    }

    void addBook(Book book) {
        byIsbn.put(book.getIsbn(), book);
    }

    Book findByIsbn(String isbn) {
        return byIsbn.get(isbn);
    }
}

Aqui Book fornece um método getIsbn(). Quem chama a classe usa addBook e findByIsbn; não precisa saber qual implementação de mapa está armazenada. O campo privado também dá à classe um único lugar para manter suas regras de adição e substituição de livros.

Verifique um resultado ausente

Se findByIsbn retornar null, nenhum livro foi encontrado. Teste o resultado antes de chamar um método nele:

Book found = library.findByIsbn("978-0-00-000000-2");
if (found != null) {
    found.setOnLoan(true);
}

Chamar setOnLoan diretamente em um resultado ausente lançaria uma NullPointerException. Um método como hasBook(isbn) é outra forma de permitir que quem chama o método verifique a existência de uma chave.

Acompanhe objetos compartilhados entre índices

Um mapa armazena uma referência a um objeto, não uma nova cópia desse objeto. Se o mesmo livro estiver em uma lista de todos os livros, em um mapa por ISBN e em um agrupamento por autor, setOnLoan(true) alterará o único livro ao qual os três se referem. Isso evita que três objetos de livro separados se tornem inconsistentes.

As próprias estruturas de coleção ainda precisam ser mantidas. Remover um livro do mapa por ISBN não remove sua referência da lista de um autor. Se uma biblioteca mantiver os dois índices, seus métodos de adição e remoção deverão atualizar ambos. Centralizar essas alterações em métodos como addBook e removeBook ajuda a manter as buscas consistentes.

Use uma tabela em um cálculo

Suponha que uma tabela de preços tenha café 2,50, chá 2,00 e muffin 3,25. Para dois cafés e um muffin:

double cost = 2 * prices.get("coffee") + prices.get("muffin");

O subtotal dos cafés é 5,00; somar 3,25 resulta em 8,25. As chaves identificam produtos, e os valores fornecem as quantias. Um produto ausente exige uma decisão explícita antes do cálculo: um valor padrão zero o trataria como gratuito sem aviso. A mesma técnica de consulta pode, portanto, precisar de uma regra para chaves ausentes diferente daquela de uma tabela de frequências.

Principais conclusões

  • Um índice encontra objetos por uma chave de identificação.
  • Use uma chave única ou agrupe explicitamente vários objetos correspondentes.
  • Índices compartilham referências a objetos, mas adições e remoções devem atualizar cada índice.
  • Mantenha mapas de dados privados e disponibilize métodos que mantenham suas regras.
3

Mantenha valores únicos com conjuntos

Às vezes a pergunta é simplesmente se um valor já apareceu antes. Conjuntos atendem diretamente a essa necessidade e também podem comparar grupos de valores, como pessoas que participam de dois eventos. A ausência de elementos duplicados muda tanto o código que você escreve quanto o significado do tamanho final. Trabalhe primeiro com pertinência, depois combine conjuntos e escolha se seus valores devem aparecer em ordem de inserção ou em ordem classificada.

3.1 Armazene valores únicos e teste a pertinência com HashSet

Um conjunto contém cada valor no máximo uma vez. Ele é adequado para perguntas como “Esse valor já apareceu antes?” ou “Quantos valores diferentes aparecem?”. Um HashSet oferece verificações de pertinência rápidas em média, sem garantir uma ordem de exibição.

Adicione e verifique valores
import java.util.HashSet;

HashSet<String> visited = new HashSet<>();
boolean first = visited.add("Oslo");
boolean second = visited.add("Lima");
boolean third = visited.add("Oslo");
visited.add("Pune");

Os três valores booleanos armazenados são true, true e false. O segundo “Oslo” corresponde a um elemento existente, portanto não é adicionado. O tamanho do conjunto é 3. Uma adição duplicada não substitui uma posição numerada, pois um conjunto não tem índice.

visited.contains("Lima") retorna true. visited.remove("Lima") remove o valor e retorna true; repetir essa remoção retorna false. Use um laço for-each para visitar os valores. Não existe get(0) para o primeiro valor de um HashSet.

Remova duplicatas de uma lista
ArrayList<Integer> values = new ArrayList<>();
values.add(3);
values.add(1);
values.add(3);
values.add(2);
values.add(1);
HashSet<Integer> distinct = new HashSet<>(values);

O conjunto tem três valores: {1, 2, 3}. Sua ordem real de iteração não é especificada. A lista original ainda tem cinco elementos porque o construtor cria uma coleção separada.

Use new LinkedHashSet<>(values) para manter a ordem das primeiras ocorrências, obtendo 3, 1, 2. Use new TreeSet<>(values) para obter valores ordenados, 1, 2, 3. Os conjuntos são escritos entre chaves aqui para destacar a pertinência; o toString() padrão de conjuntos em Java usa colchetes.

Detecte a primeira repetição

O resultado de add pode realizar o teste de pertinência e a inserção juntos:

HashSet<Integer> seen = new HashSet<>();
for (int number : numbers) {
    if (!seen.add(number)) {
        System.out.println(number);
        break;
    }
}

Para [4, 7, 2, 7, 4], o laço exibe 7. Esse é o primeiro valor encontrado uma segunda vez, embora 4 tenha aparecido antes na sequência. Antes de 7 se repetir, o conjunto contém 4, 7 e 2. A inserção que falha provoca a interrupção.

Saiba o que um conjunto não pode informar

Verificar contains antes de cada add é desnecessário porque add já trata duplicatas. Uma lista com uma verificação contains também pode manter valores únicos, mas cada busca na lista pode percorrer todos os elementos armazenados. Um HashSet expressa a regra diretamente.

A igualdade importa para seus próprios objetos. Um HashSet<Point> precisa de equals baseado no conteúdo e de um hashCode compatível para reunir pontos criados separadamente com coordenadas iguais. Sem essas sobrescritas, instâncias separadas permanecem como elementos separados.

Por fim, size() mede valores distintos, não ocorrências. As nove palavras de “o gato viu o cão e o gato correu” produzem seis palavras distintas. Um conjunto não informa mais que “o” ocorreu três vezes; use um mapa de frequências quando essas contagens importarem.

Principais conclusões

  • HashSet armazena valores únicos sem índice nem ordem garantida.
  • add retorna falso quando um valor igual já está presente.
  • Um conjunto criado por cópia remove duplicatas sem alterar a lista original.
  • Use o resultado de add para detectar um valor repetido.
  • O tamanho de um conjunto conta valores distintos; frequências exigem um mapa.

3.2 Combine conjuntos e mantenha sua ordem

Conjuntos podem descrever grupos e comparar seus membros. Se duas listas de eventos contiverem a mesma pessoa várias vezes, um conjunto primeiro reduz cada lista às pessoas que participaram. As operações de conjuntos então respondem a perguntas sobre qualquer um dos eventos, ambos ou apenas um deles.

Combine dois grupos

Considere que segunda-feira seja {Ana, Ben, Cai, Dee} e terça-feira seja {Ben, Dee, Eva}.

PerguntaMétodo em uma cópia de segunda-feiraResultado
Quem participou em qualquer um dos dias?addAll(tuesday){Ana, Ben, Cai, Dee, Eva}
Quem participou nos dois dias?retainAll(tuesday){Ben, Dee}
Quem participou somente na segunda-feira?removeAll(tuesday){Ana, Cai}

Essas operações são união, interseção e diferença. Elas alteram o conjunto receptor e retornam um valor booleano que indica se ele foi alterado. Elas não retornam um novo conjunto como resultado.

Preserve o original

Faça uma cópia antes de alterar os membros se segunda-feira ainda for necessária:

HashSet<String> both = new HashSet<>(monday);
both.retainAll(tuesday);

both começa com os quatro nomes de segunda-feira. retainAll remove Ana e Cai porque eles não estão em terça-feira. O próprio conjunto de segunda-feira permanece inalterado. Para encontrar quem participou somente na terça-feira, comece com uma cópia de terça-feira e remova os nomes de segunda-feira, obtendo {Eva}. A diferença tem uma direção; invertê-la muda a pergunta.

Verifique subconjuntos e igualdade

monday.containsAll(group) verifica se todos os valores de group estão presentes em segunda-feira. Para {Ben, Dee}, retorna true: esse grupo é um subconjunto de segunda-feira. Isso não exige que segunda-feira contenha apenas essas duas pessoas.

Dois conjuntos são iguais quando seus elementos correspondem, independentemente da ordem de inserção ou da implementação. Um HashSet que contém “x” e “y” é igual a um TreeSet que contém “y” e “x”. A pertinência determina a igualdade de conjuntos, portanto a ordem por si só não pode torná-los diferentes.

Escolha uma ordem para o percurso
ImplementaçãoOrdem ao visitar os elementos
HashSetSem garantia
LinkedHashSetOrdem de inserção
TreeSetOrdem classificada

Os três evitam duplicatas. Use LinkedHashSet quando a primeira ocorrência de cada nome for importante. Use TreeSet quando cada percurso já precisar estar ordenado. Para cadeias de caracteres, a ordenação natural segue os códigos dos caracteres: formas minúsculas e maiúsculas não se comportam como um único alfabeto sem distinção entre elas.

Um TreeSet com seu construtor padrão precisa de elementos que tenham uma comparação natural, como cadeias de caracteres, números ou objetos que implementem Comparable. Nesse conjunto, um resultado de comparação igual a zero indica uma duplicata. Uma classe que não fornece comparação natural causa uma ClassCastException quando um de seus objetos é inserido. Fornecer um comparador explícito é outra forma de definir a ordem de uma coleção em árvore; os exemplos com construtor padrão usam a ordem natural.

Principais conclusões

  • addAll, retainAll e removeAll alteram o conjunto receptor.
  • Copie primeiro um conjunto quando seus membros originais ainda forem necessários.
  • containsAll verifica um subconjunto; a igualdade de conjuntos ignora a ordem.
  • Escolha implementações baseadas em hash, vinculadas ou em árvore para obter, respectivamente, ordem não especificada, de inserção ou classificada.
4

Programe com as interfaces List, Set e Map

O tipo à esquerda de uma declaração de coleção informa ao restante do programa quais operações ele pode usar. A classe à direita fornece essas operações e pode garantir uma ordem específica. Aprender a interpretar os dois lados torna o código com coleções mais fácil de alterar e os métodos mais fáceis de reutilizar. Isso também ajuda a explicar por que uma lista, um conjunto e um mapa se comportam de maneira diferente mesmo quando contêm dados de aparência semelhante.

4.1 Declare variáveis e parâmetros com tipos de interface

Uma interface descreve operações fornecidas por uma classe que a implementa. Ela permite que uma variável descreva o que o código precisa, deixando a escolha do armazenamento para uma classe concreta. List, Set e Map são interfaces relacionadas a coleções em java.util.

Interprete os dois lados de uma declaração
List<String> names = new ArrayList<>();
Set<String> tags = new HashSet<>();
Map<String, Integer> counts = new HashMap<>();

O lado esquerdo declara o tipo da variável. O lado direito cria um objeto de uma classe que implementa esse tipo. Importe ambos os tipos, como java.util.List e java.util.ArrayList. Você não pode escrever new List<>() ou new Map<>(): uma interface não é um objeto concreto que possa ser construído.

O código que usa counts pode chamar put, get e entrySet porque Map os declara. Se chaves em ordem alfabética se tornarem úteis, altere a construção para new TreeMap<>(). As chamadas existentes continuam compilando. Sua ordem pode mudar porque as implementações podem oferecer garantias diferentes de ordem; a interface não as torna idênticas em todos os comportamentos.

Aceite a capacidade de que um método precisa

Um método que apenas conta palavras longas pode receber uma Collection:

static int countLong(Collection<String> words, int min) {
    int count = 0;
    for (String word : words) {
        if (word.length() >= min) {
            count++;
        }
    }
    return count;
}

Para [“a”, “tree”, “house”] e um mínimo de 4, ele retorna 2. O mesmo método pode receber um ArrayList, um LinkedList, um HashSet ou List.of(...) porque apenas lê os elementos. Um conjunto pode já ter removido duplicatas, portanto pode fornecer dados de entrada diferentes dos de uma lista.

Usar um parâmetro de tipo de interface evita exigir uma classe específica de armazenamento quando o método não precisa dela. Se posições forem necessárias, aceite List. Se consultas por chave forem necessárias, aceite Map.

Conheça os limites do tipo declarado
List<String> names = new ArrayList<>();
names.ensureCapacity(100);  // does not compile

O objeto é um ArrayList, mas List não declara ensureCapacity. O compilador verifica o tipo declarado da variável. Use um tipo de classe concreta quando sua operação especial for realmente necessária; não altere parâmetros de listas comuns apenas para corresponder à classe usada por quem chama o método.

Posicione Map ao lado de Collection

List e Set estendem Collection, que descreve um grupo de elementos. Ela declara métodos como add, remove, contains, size, isEmpty, addAll e clear. A possibilidade de fazer uma alteração depende da coleção concreta.

Map não estende Collection. Ele armazena associações e fornece visões que são coleções: keySet() é um Set, values() é uma Collection e entrySet() é um Set de entradas. Passe counts.values() a um método que precise de uma coleção de valores, não o próprio counts.

Uma classe pode implementar várias interfaces. LinkedList implementa tanto List quanto Deque, uma interface de fila de duas extremidades. Sua própria classe indica as interfaces que se compromete a implementar depois de implements, como em class Member implements Comparable<Member>.

Principais conclusões

  • Declare a interface necessária à esquerda e construa uma classe que a implemente à direita.
  • Parâmetros de tipo de interface aceitam diferentes implementações com as operações necessárias.
  • Uma variável disponibiliza apenas os métodos declarados por seu tipo.
  • List e Set estendem Collection; Map fornece visões de coleção.

4.2 Conheça as garantias de List, Set e Map

Escolha uma interface pelas regras de que seus dados precisam. Conteúdos de aparência semelhante não tornam uma lista, um conjunto e um mapa intercambiáveis: cada um atribui um significado diferente a posições, repetições e igualdade.

Compare as garantias
InterfaceO que armazenaRegra importante
ListElementos em posições a partir de 0Elementos repetidos são permitidos
SetElementos distintosNão tem operação get por índice
MapPares chave–valorChaves são únicas; valores podem se repetir

ArrayList e LinkedList implementam List. HashSet, LinkedHashSet e TreeSet implementam Set. HashMap, LinkedHashMap e TreeMap implementam Map. As versões baseadas em hash não garantem ordem de percurso; as versões vinculadas preservam a ordem de inserção; as versões em árvore mantêm elementos ou chaves ordenados. Inserir novamente uma chave existente em um LinkedHashMap comum, ordenado por inserção, mantém a posição dessa chave.

Examine com cuidado a remoção em listas de inteiros

Uma List<Integer> tem duas sobrecargas relevantes:

List<Integer> numbers = new ArrayList<>(List.of(1, 5, 7));
numbers.remove(1);

O argumento 1 é um int, portanto Java remove o índice 1: o valor 5. O resultado é [1, 7]. Começando novamente com [1, 5, 7], numbers.remove(Integer.valueOf(1)) seleciona a remoção por valor e deixa [5, 7]. O objeto empacotador deixa clara a sobrecarga pretendida.

Compare conteúdos com a regra correta

Duas listas são iguais quando os mesmos elementos aparecem na mesma ordem. Um ArrayList [1, 2] é igual a um LinkedList [1, 2], mas não a uma lista [2, 1]. Dois conjuntos comparam a pertinência, ignorando a ordem. Dois mapas comparam suas associações, portanto a ordem de inserção não afeta a igualdade dos mapas. Suas classes concretas podem ser diferentes enquanto seus conteúdos são iguais segundo a regra da interface.

Reconheça coleções não modificáveis
List<String> labels = List.of("a", "b");
Set<Integer> levels = Set.of(1, 2, 3);
Map<String, Double> prices = Map.of("tea", 2.0, "coffee", 2.5);

Essas fábricas retornam coleções não modificáveis. Tentativas de adicionar, remover, substituir ou ordenar seu conteúdo lançam UnsupportedOperationException. Map.of aceita até dez pares chave–valor.

As três rejeitam elementos, chaves ou valores null com NullPointerException. Set.of rejeita elementos duplicados e Map.of rejeita chaves duplicadas com IllegalArgumentException. List.of permite duplicatas porque uma lista pode repetir um elemento. Os conjuntos e mapas produzidos pelas fábricas têm ordem de iteração não especificada.

Copie quando alterações forem necessárias

new ArrayList<>(labels) cria uma lista modificável com os mesmos elementos. new HashSet<>(someList) e new HashMap<>(someMap) também criam estruturas de coleção separadas.

Essas cópias são superficiais: elas contêm as mesmas referências aos elementos. Remover um elemento de uma cópia deixa a estrutura original intacta, mas alterar um objeto mutável por meio de qualquer uma das coleções altera o objeto compartilhado. Uma coleção não modificável impede alterações em sua estrutura; ela não congela todos os objetos armazenados nela.

Principais conclusões

  • Listas têm posições e duplicatas; conjuntos têm elementos distintos; mapas têm chaves únicas.
  • remove(1) em uma lista de inteiros remove por índice; remove(Integer.valueOf(1)) remove por valor.
  • A igualdade de listas verifica a ordem; a igualdade de conjuntos e mapas verifica o conteúdo sem considerar a ordem de inserção.
  • As fábricas of produzem coleções não modificáveis e rejeitam valores nulos.
  • Set.of rejeita elementos duplicados; Map.of rejeita chaves duplicadas.
  • Uma cópia modificável tem uma estrutura de coleção separada, mas compartilha as referências aos elementos.
5

Ordene coleções com Comparable

A ordenação coloca valores em uma ordem que outras partes do código podem usar. Números e cadeias de caracteres já têm sua ordem natural; objetos de suas próprias classes precisam de uma regra explícita. Acompanhe uma lista durante uma ordenação e depois escreva uma comparação que trate números, texto e empates com segurança. A regra importa além das listas: um conjunto ou mapa ordenado também a usa para decidir quando dois elementos ou chaves ocupam a mesma posição.

5.1 Ordene listas de números e cadeias de caracteres

Uma lista mantém uma ordem, mas essa ordem pode apenas refletir como os valores chegaram. A ordenação reorganiza a lista usando uma regra de comparação. Java já fornece uma ordem natural para números e cadeias de caracteres.

Ordene uma lista modificável na própria lista
List<Double> values = new ArrayList<>(List.of(3.5, -1.0, 2.25));
Collections.sort(values);

Importe java.util.Collections. A mesma lista agora contém [-1,0; 2,25; 3,5]. A ordenação retorna void, portanto values = Collections.sort(values) não compila. values.sort(null) também ordena em ordem natural. Para um vetor, use Arrays.sort(array); um vetor contendo 5, 2 e 8 passa a conter 2, 5, 8.

Preveja a ordem de cadeias caractere por caractere

A comparação de cadeias examina o primeiro caractere diferente. Se uma cadeia for prefixo de outra, a mais curta vem primeiro. Assim, “apple” vem antes de “apples”.

A lista [“pear”, “Banana”, “apple”, “10”, “9”] é ordenada como [“10”, “9”, “Banana”, “apple”, “pear”]. Para esses caracteres, algarismos precedem letras maiúsculas, e maiúsculas precedem minúsculas. “10” vem antes de “9” porque “1” vem antes de “9”; a ordem de cadeias não interpreta cadeias de algarismos como números inteiros. Armazene dados numéricos como números quando a ordem numérica for necessária.

Use ordens alternativas prontas
names.sort(String.CASE_INSENSITIVE_ORDER);
values.sort(Collections.reverseOrder());

A primeira chamada ordena [“pear”, “Banana”, “apple”] como [“apple”, “Banana”, “pear”] sem alterar as letras maiúsculas e minúsculas armazenadas. A segunda usa a ordem natural decrescente. Os números 4, 9 e 1 tornam-se 9, 4 e 1. Esses argumentos são comparadores, objetos que fornecem uma ordem alternativa.

Collections.reverse(list) apenas inverte a sequência atual. Ele produz ordem decrescente se essa sequência já estava ordenada de forma crescente; sozinho, não ordena uma lista arbitrária.

Mantenha os empates estáveis

A ordenação de listas é estável: elementos considerados iguais na comparação mantêm sua ordem relativa anterior. Se uma comparação apenas por pontuação empatar duas pessoas, a ordem anterior delas na lista permanece. A estabilidade preserva essa ordem de entrada; ela não cria um critério de desempate alfabético.

Reconheça falhas e atalhos

Uma lista criada com List.of(...) não pode ser ordenada na própria lista. Primeiro copie-a para um ArrayList. Para uma classe sem Comparable, Collections.sort(list) falha na verificação de tipos durante a compilação. Chamar list.sort(null) em objetos desse tipo falha em tempo de execução com ClassCastException quando a comparação é necessária.

Collections.max(collection) e Collections.min(collection) encontram o maior e o menor elemento em ordem natural sem reorganizar a coleção. Eles lançam NoSuchElementException para uma coleção vazia.

Para obter chaves de mapa ordenadas, copie map.keySet() para um ArrayList e ordene a cópia, ou use um TreeMap. Ordenar uma lista copiada de chaves deixa inalterada a ordem de iteração do próprio mapa.

Principais conclusões

  • Collections.sort altera uma lista modificável na própria lista e retorna void.
  • A ordem natural de cadeias compara caracteres, não os valores numéricos no texto.
  • Use comparadores prontos para ordem inversa ou sem distinção entre maiúsculas e minúsculas.
  • A ordenação estável preserva a ordem relativa anterior dos elementos empatados.
  • Copie uma lista não modificável antes de ordená-la.
  • min e max encontram valores extremos sem ordenar.

5.2 Implemente Comparable em sua própria classe

Java não consegue adivinhar se um membro deve vir primeiro pelo nome, pela altura ou por outro campo. Implemente Comparable para dar à classe uma ordem natural. O código de ordenação pode então pedir que cada objeto se compare a outro objeto dessa classe.

Escreva o método de comparação
class Member implements Comparable<Member> {
    private String name;
    private int height;

    Member(String name, int height) {
        this.name = name;
        this.height = height;
    }

    @Override
    public int compareTo(Member other) {
        return Integer.compare(this.height, other.height);
    }
}

A altura é medida em centímetros. Comparable<Member> especifica que o outro objeto é um Member; nenhuma conversão explícita é necessária. public int compareTo(Member other) é o método exigido. A interface padrão Comparable está em java.lang, portanto não precisa ser importada.

Para a.compareTo(b), um resultado negativo coloca a antes de b, zero os coloca na mesma posição de comparação e um resultado positivo coloca a depois de b. Apenas o sinal importa: -35 é um resultado negativo tão válido quanto -1.

Acompanhe a ordem

Com a comparação por altura, Ana 172, Ben 165 e Cai 180 são ordenados como Ben 165, Ana 172 e Cai 180. Para colocar os membros mais altos primeiro, inverta os argumentos:

return Integer.compare(other.height, this.height);

Altere a regra de forma deliberada. Inverter os argumentos inverte o sentido desse campo; isso não muda o significado da altura nem altera os dados de qualquer membro.

Compare valores numéricos inteiros com segurança

A subtração parece conveniente, mas pode retornar o sinal errado quando ocorre estouro de um int. Para -2.000.000.000 e 2.000.000.000, subtrair o segundo do primeiro produz, por estouro, 294.967.296, um resultado positivo. Integer.compare retorna corretamente um resultado negativo.

Para campos decimais, use Double.compare(this.price, other.price). Converter explicitamente uma diferença para int perde informação: (int) (1.8 - 1.5) é 0, portanto preços diferentes tornam-se um empate na comparação. Um método auxiliar de comparação preserva a ordem sem truncar a diferença.

Compare texto e reutilize a regra

Para ordenar por nome, retorne this.name.compareTo(other.name). Ele segue a ordem dos caracteres da cadeia. compareToIgnoreCase fornece comparação de texto sem distinção entre maiúsculas e minúsculas quando essa é a regra pretendida para o campo.

Depois que uma classe define uma ordem natural, operações como Collections.sort, Collections.max e as comparações padrão de TreeSet ou TreeMap podem usá-la. Uma classe também pode implementar outras interfaces, separadas por vírgulas depois de implements.

Há uma ordem natural para a classe, não um compareTo diferente selecionado para cada lista. Use objetos comparadores separados quando um contexto precisar de ordem por nome e outro de ordem por altura. Uma comparação apenas por altura também empata todas as alturas iguais; decidir se esse empate é aceitável torna-se especialmente importante em conjuntos ordenados.

Principais conclusões

  • Implemente Comparable<YourClass> com um método público compareTo.
  • Resultados negativo, zero e positivo significam, respectivamente, antes, empate e depois.
  • Use Integer.compare e Double.compare para uma ordenação numérica segura.
  • Inverta os argumentos da comparação para inverter o sentido de um campo.
  • Uma classe tem uma ordem natural; comparadores fornecem outras ordens.

5.3 Resolva empates e use conjuntos e mapas ordenados

Uma comparação principal muitas vezes deixa empates. Dois filmes podem ter o mesmo ano ou dois jogadores podem ter a mesma pontuação. Um critério de desempate dá vez ao campo seguinte somente quando os campos anteriores são considerados iguais na comparação.

Compare os campos em ordem de prioridade
@Override
public int compareTo(Film other) {
    int byYear = Integer.compare(this.year, other.year);
    if (byYear != 0) {
        return byYear;
    }
    return this.title.compareTo(other.title);
}

O ano é a regra principal. O título só importa quando os anos empatam. Up (2009), Avatar (2009) e Alien (1979) são ordenados como Alien (1979), Avatar (2009), Up (2009). Comparar os títulos primeiro daria a eles prioridade sobre o ano e atenderia a uma tarefa de ordenação diferente.

Os sentidos podem ser diferentes para cada campo. Para colocar as maiores pontuações primeiro e os nomes de A a Z, comece com Integer.compare(other.points, this.points). Se o resultado for zero, retorne this.name.compareTo(other.name). Inverter toda a lista final também inverteria os nomes dentro das pontuações empatadas.

Entenda a regra de duplicatas de um conjunto ordenado

Um TreeSet<Member> padrão usa a comparação natural tanto para ordenar elementos quanto para decidir quando um elemento já está presente. Se Member.compareTo usar apenas a altura, Ana 172 e Dee 172 terão comparação igual a zero. Adicionar Ana retorna true; adicionar Dee retorna false. Ana permanece como elemento armazenado mesmo que equals considere as duas integrantes diferentes.

Uma lista pode manter os dois objetos empatados; um conjunto em árvore dá a eles uma única posição de comparação. Adicione o critério de desempate necessário se eles precisarem ser distintos no conjunto.

Alinhe a comparação à igualdade

Uma ordem é consistente com equals quando a comparação retorna zero se, e somente se, equals retorna verdadeiro. Para uma classe cuja igualdade usa altura e nome, comparar primeiro a altura e depois o nome pode atender a essa regra. Se a igualdade usar outra identidade, como um ID de membro, adicionar apenas o nome como critério de desempate não estabelece a consistência.

A comparação também deve se comportar como uma ordem válida. Se a vem antes de b, a comparação inversa deve colocar b depois de a. Se a está antes de b e b antes de c, a deve estar antes de c. Usar métodos auxiliares de comparação de campos completos em uma ordem fixa de prioridade ajuda a cumprir essas regras. Um método inconsistente pode ordenar resultados incorretamente ou fazer uma ordenação lançar IllegalArgumentException.

Mantenha as chaves do mapa ordenadas também

Um TreeMap ordena chaves, não valores. Para as contagens de palavras de “o gato viu o cão e o gato correu”, a primeira chave é “cão” e a última é “viu”. firstKey() e lastKey() fornecem esses extremos. Declare um TreeMap ou uma interface apropriada de mapa ordenado ao chamar métodos que o Map comum não declara.

A comparação de chaves também define quais chaves correspondem. Uma segunda chave cuja comparação resulta em zero atualiza a associação existente, mesmo quando equals distingue os objetos. Coleções em árvore com comportamento padrão exigem elementos ou chaves comparáveis naturalmente; inserir um objeto sem comparação adequada lança ClassCastException. Um comparador fornecido explicitamente pode definir outra ordem.

Principais conclusões

  • Compare primeiro o campo principal e consulte os campos seguintes apenas em caso de empate.
  • Inverta apenas os campos que precisam de ordem decrescente.
  • Coleções em árvore tratam uma comparação igual a zero como o mesmo elemento ou a mesma chave.
  • A consistência com equals exige que a comparação seja zero exatamente quando a igualdade for verdadeira.
  • TreeMap ordena chaves; seus métodos de extremidade retornam as chaves extremas.
  • Uma comparação deve inverter os sinais de forma consistente e preservar a ordem entre três elementos.
6

Escolha a coleção adequada para uma tarefa

A escolha de uma coleção começa pelas perguntas que o programa deve responder: por posição, por pertinência ou por uma chave separada. Ordem e duplicatas restringem ainda mais a escolha. Depois que os dados se ajustarem à tarefa, compare como as operações frequentes crescem à medida que chegam mais valores. Uma pequena alteração, como criar um conjunto antes de um laço, pode eliminar buscas repetidas sem tornar o programa mais difícil de ler.

6.1 Compare o custo de operações comuns em coleções

O custo de uma operação descreve como seu trabalho cresce com o número de elementos armazenados. Ele ajuda a identificar código que é rápido para um exemplo pequeno, mas lento quando a coleção se torna grande.

Compare o crescimento, não os segundos

O tempo constante, O(1), permanece aproximadamente independente do tamanho da coleção. O tempo linear, O(n), pode crescer em proporção ao número de elementos. O tempo logarítmico, O(log n), cresce lentamente à medida que o tamanho aumenta. Essas designações descrevem o crescimento, não tempos exatos de execução em um computador específico.

ColeçãoOperaçãoCusto
ArrayListget(i), set(i, x)Constante
ArrayListAdicionar ao finalConstante em média
ArrayListcontains, indexOf, remover por valorLinear
ArrayListInserir ou remover perto do inícioLinear
HashMap / HashSetConsulta básica por chave ou pertinência, inserção, remoçãoConstante em média com hashes bem distribuídos
TreeMap / TreeSetConsulta básica, inserção, remoçãoLogarítmico
LinkedListAdicionar ou remover em qualquer extremidadeConstante
LinkedListget(i) em geralLinear

Uma busca em ArrayList pode verificar todos os elementos; alterações no início deslocam os elementos seguintes. Um LinkedList precisa percorrer a lista até uma posição, portanto o acesso repetido por índice pode ser custoso. ArrayList é uma escolha padrão útil para o trabalho comum com listas.

Identifique o percurso repetido

Suponha que um programa verifique 10.000 nomes em uma lista que contém 100.000 nomes. Chamar list.contains(name) para cada nome pode exigir até 1.000.000.000 de verificações de igualdade. Uma chamada de método que parece rápida ainda é uma busca completa quando usada dessa forma.

Construa um conjunto para verificar a pertinência uma única vez:

Set<String> allowed = new HashSet<>(allowedNames);
int matches = 0;
for (String name : incomingNames) {
    if (allowed.contains(name)) {
        matches++;
    }
}

Há trabalho para construir o conjunto de 100.000 elementos, seguido de 10.000 verificações de pertinência em tempo constante em média. Contando as duas etapas, o total cresce aproximadamente com a soma dos tamanhos das duas entradas, em vez de seu produto. Reconstruir o conjunto dentro do laço repetiria o trabalho de preparação e eliminaria esse benefício.

Interprete corretamente as garantias médias

Operações baseadas em hash dependem de chaves cujos códigos de dispersão distribuam bem os valores. Retornar um código de dispersão constante para todos os objetos ainda pode satisfazer as regras de igualdade, mas torna a consulta lenta. Isso não é uma maneira sem custo de evitar escrever um método de hash útil.

Coleções em árvore mantêm a ordem classificada com operações básicas logarítmicas. Dobrar o número de elementos acrescenta apenas uma pequena quantidade de trabalho à busca. Para 100.000 elementos, um logaritmo de base dois é aproximadamente 16,6; isso indica a escala da busca, não uma garantia exata de 17 comparações em toda consulta em árvore de Java.

Considere a tarefa inteira

Construir um conjunto adicional custa tempo e memória. Para poucos elementos ou uma única consulta, a lista original pode ser suficiente. Para verificações repetidas de pertinência, um conjunto reutilizável frequentemente elimina o principal custo. Comece pelo comportamento necessário e depois examine as operações repetidas com mais frequência.

Principais conclusões

  • As designações de crescimento descrevem como o custo aumenta, não um número medido de segundos.
  • ArrayList oferece acesso rápido por índice, mas buscas e alterações no início são lineares.
  • Consultas baseadas em hash são constantes em média com códigos de dispersão adequados; consultas em árvores são logarítmicas.
  • Construa um conjunto de pertinência uma vez para substituir buscas repetidas em listas.
  • Inclua o tempo de preparação e a memória ao comparar soluções completas.

6.2 Selecione uma coleção que atenda à tarefa

A coleção adequada mantém as informações de que o programa precisa e facilita a expressão de suas principais perguntas. Decida as regras dos dados antes de escolher o nome de uma classe conhecida.

Pergunte o que identifica um item
Necessidade principalEscolha inicialExemplo
Encontrar um valor por uma chave separadaMapCódigo de produto associado a preço
Testar pertinência sem duplicatasSetNomes de usuário ocupados
Manter posições, ordem ou itens repetidosListUma playlist que repete músicas
Manter um número fixo de posiçõesVetorDoze medições mensais de precipitação

Um double[12] pode armazenar a precipitação em milímetros quando cada posição corresponde a um mês conhecido. Um mapa cujas chaves são apenas as posições 0, 1, 2 e assim por diante acrescenta uma camada que uma lista ou um vetor já fornece.

Escolha a ordem necessária

Para mapas e conjuntos, use HashMap ou HashSet quando nenhuma ordem for necessária, LinkedHashMap ou LinkedHashSet para ordem de inserção e TreeMap ou TreeSet para chaves ou elementos ordenados. Para uma lista de uso geral, comece com ArrayList.

Contagens de palavras exibidas em ordem alfabética combinam com um TreeMap<String, Integer>. Uma lista de marcadores distintos na ordem em que foram vistos pela primeira vez combina com LinkedHashSet<String>. Músicas repetidas exigem uma lista, mesmo que também estejam armazenadas em outro lugar em um conjunto: descartar repetições alteraria a playlist.

Combine coleções quando os dados tiverem camadas

Alunos por curso podem ser representados por Map<String, List<String>>; cada valor é uma lista ordenada de matrículas. Marcadores por artigo podem ser representados por Map<String, Set<String>>; cada artigo recebe marcadores distintos. Uma tabela de classificação pode ser uma List<Player> ordenada pela comparação natural do jogador.

As escolhas externas e internas respondem a perguntas diferentes. Se os cursos devem ser listados em ordem alfabética e os alunos mantidos em ordem de matrícula, use um TreeMap por fora e uma lista por dentro. Ordenar as chaves não ordena as listas. Se registros de matrícula duplicados devem ser ignorados, use um conjunto para os grupos internos.

Mantenha dados relacionados juntos

Duas listas paralelas, uma de nomes e outra de números de telefone, dependem de posições correspondentes. Remover um nome sem seu número desfaz todos os pares seguintes. Se os nomes identificarem pessoas de forma única, um mapa pode guardar a associação. Se nomes se repetirem ou vários campos pertencerem a uma pessoa, mantenha objetos de pessoas em uma lista ou indexe-os por um ID único.

Pesquisar uma lista repetidamente por um campo é outro sinal de que vale considerar um mapa como índice. Mantenha também a lista se a ordem de exibição e as entradas repetidas importarem, mas atualize as duas estruturas em conjunto quando dados forem adicionados ou removidos.

Verifique as regras dos elementos e o tipo declarado

Use uma declaração com interface, como Map<String, Double> prices = new HashMap<>();, para que quem usa o mapa dependa das operações necessárias. Coleções baseadas em hash precisam de uma igualdade adequada e de códigos de dispersão compatíveis para chaves ou elementos personalizados. Coleções em árvore com comportamento padrão precisam de uma comparação natural que distinga exatamente os valores que a coleção deve manter. Essas regras fazem parte de garantir que a coleção escolhida represente os dados pretendidos.

Principais conclusões

  • Escolha mapas para consultas por chave, conjuntos para pertinência e listas para posições ou repetições.
  • Vetores podem conter um número fixo de posições, inclusive com valores primitivos.
  • Escolha deliberadamente entre ordem de inserção e ordem classificada.
  • Coleções aninhadas permitem que as chaves externas e os grupos internos sigam regras diferentes.
  • Mantenha campos relacionados juntos e atualize vários índices por meio de métodos compartilhados.
  • Ajuste as regras de igualdade e comparação aos valores que a coleção deve manter.

Exercícios resolvidos de HashMaps e coleções em Java

6 Lições Interativas

1

Acompanhe um mapa de estoque do armazenamento à consulta

13 passos
Acompanhe alterações, examine entradas com segurança e faça chaves personalizadas serem encontradas.
  1. 1
    IntroduçãoComece com uma pergunta sobre um produto

    Um programa de estoque precisa responder: “Quantas pastas estão disponíveis?”. Um mapa usa o nome do produto como chave e sua quantidade como valor. Acompanhe um mapa durante uma substituição, uma consulta a uma chave ausente e uma limpeza. Depois examine por que uma chave personalizada pode falhar mesmo quando seus campos parecem corretos. Cada consulta depende do que Java considera a mesma chave.

  2. 2
    ExplicaçãoCrie uma associação por chave

    Crie HashMap<String, Integer> stock = new HashMap<>();. String descreve as chaves; Integer descreve os valores. O mapa usa tipos de referência, portanto int não pode ser o argumento de tipo do valor. Java empacota um literal como 6 quando stock.put("folder", 6) o armazena. O diamante à direita permite que Java infira os dois tipos.

  3. 3
    ExemploSubstitua uma quantidade

    Execute estas atualizações em ordem:

    stock.put("folder", 6);
    stock.put("clip", 11);
    Integer old = stock.put("folder", 8);
    

    A última chamada encontra a chave existente de pasta, armazena 8 e retorna 6 para old. Ainda há duas chaves. Um mapa registra o valor mais recente de uma chave; ele não soma quantidades automaticamente nem mantém um histórico delas.

  4. 4
    DesafioLeia sem inserir

    Quais são os valores de n e stock.size() depois desta leitura? O mapa ainda contém pasta 8 e clipe 11.

    int n = stock.getOrDefault("tape", 0);
    

    ---reveal---

    n é 0, e o tamanho permanece 2. O valor padrão é um resultado para uma chave ausente, não uma entrada inserida. Ler com get("tape") retorna null, que não pode ser desempacotado em um int.

  5. 5
    ExplicaçãoLeia os pares juntos

    Um laço sobre entradas fornece cada chave e seu valor juntos:

    for (Map.Entry<String, Integer> e : stock.entrySet()) {
        System.out.println(e.getKey() + ": " + e.getValue());
    }
    

    Importe java.util.Map. O laço pode mostrar as duas associações sem um get separado. Se apenas um total for necessário, percorra stock.values() e some as quantidades; quantidades repetidas ainda contribuem separadamente.

  6. 6
    Ideia-chaveNão presuma qual será a primeira entrada

    A saída pode listar pasta antes de clipe ou clipe antes de pasta. HashMap não garante nenhuma das duas ordens. Um resultado como uma soma não é afetado, mas uma regra de “manter a primeira pontuação empatada” pode depender do percurso. Escolha LinkedHashMap para ordem de inserção ou TreeMap para chaves ordenadas e defina uma regra explícita para máximos empatados quando o vencedor precisar ser previsível.

  7. 7
    ExemploExclua durante o percurso

    Suponha que pasta agora seja 0 e clipe seja 11. Remova quantidades zero com um iterador:

    Iterator<Map.Entry<String, Integer>> it =
        stock.entrySet().iterator();
    while (it.hasNext()) {
        if (it.next().getValue() == 0) {
            it.remove();
        }
    }
    

    O iterador remove sua entrada atual e continua com segurança. Chamar stock.remove durante um percurso for-each pode, em vez disso, provocar ConcurrentModificationException.

  8. 8
    DesafioSepare uma cópia das chaves

    Antes da limpeza, keys é criada com new ArrayList<>(stock.keySet()). Se keys.remove("folder") for chamado, o que acontece com o mapa de estoque?

    ---reveal---

    O mapa mantém sua associação para pasta. keys é uma lista separada das chaves que existiam quando ela foi copiada. Remover do próprio stock.keySet() removeria a entrada do mapa, pois esse objeto é uma visão vinculada.

  9. 9
    ExemploExperimente uma chave personalizada

    Imagine que Bin tenha os campos row e column e nenhuma sobrescrita de igualdade. Armazene um rótulo usando new Bin(3, 4) e depois consulte-o usando outro new Bin(3, 4). A consulta retorna null. São dois objetos diferentes, e o Object.equals herdado usa identidade. Valores de campos correspondentes ainda não foram transformados em uma regra de correspondência de chaves.

  10. 10
    ExplicaçãoFaça a igualdade e o hash concordarem

    Para definir a identidade de um compartimento pelas coordenadas, sobrescreva equals(Object other) para comparar linha e coluna e sobrescreva hashCode() usando os mesmos campos, por exemplo, Objects.hash(row, column). Coordenadas iguais devem produzir códigos de dispersão iguais. Um código de dispersão correspondente, por si só, não estabelece igualdade; a verificação de igualdade ainda distingue chaves com coordenadas diferentes.

  11. 11
    DesafioIdentifique uma sobrecarga

    Uma classe define public boolean equals(Bin other) e hashCode() a partir de suas coordenadas. Por que uma consulta com um compartimento separado, aparentemente igual, ainda pode falhar?

    ---reveal---

    O parâmetro deve ser Object para sobrescrever o método de igualdade de Java. O método com parâmetro Bin é uma sobrecarga, deixando em vigor a igualdade por identidade herdada. Adicionar @Override a essa assinatura incorreta faz o compilador revelar o erro.

  12. 12
    DesafioCorrija um projeto com chave mutável

    Uma chave de compartimento usa linha e coluna em ambos os métodos de igualdade. O programa altera sua linha enquanto ela está armazenada e depois não consegue encontrar seu rótulo. Como ele deve atualizar a localização e depois remover rótulos vazios com segurança durante o percurso?

    ---reveal---

    Remova a associação antes de alterar a chave e depois insira-a novamente. Para a limpeza durante o percurso, use o próprio método de remoção do iterador de entradas. Uma identidade de chave estável e um percurso seguro resolvem partes diferentes dessa atualização.

  13. 13
    RecapitulaçãoMantenha uma lista de verificação para atualizar mapas

    Para uma consulta a uma chave ausente, decida se um valor padrão ou uma verificação explícita de ausência é adequado à tarefa. Para um laço, decida se a ordem importa e se chaves serão removidas. Para uma chave personalizada, verifique a assinatura exata de equals(Object), os campos correspondentes usados no hash e a estabilidade da identidade. Essas verificações localizam causas diferentes do mesmo sintoma: uma associação que o programa não consegue usar como esperado.

2

Construa informações de participação à medida que os registros chegam

12 passos
Conte registros, agrupe participantes distintos e mantenha índices de consulta consistentes.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoTransforme registros recebidos em respostas úteis
  2. 2
    ExemploInicie uma contagem de sessões
  3. 3
    ExemploDistinga sessões distintas de registros
  4. 4
    DesafioCorrija uma contagem reiniciada
  5. 5
    ExplicaçãoCrie um grupo uma única vez
  6. 6
    ExemploAcompanhe a referência interna
  7. 7
    DesafioEncontre o erro de grupo compartilhado
  8. 8
    ExplicaçãoIndexe por uma chave de identificação
  9. 9
    Ideia-chaveAltere um objeto em vários lugares
  10. 10
    DesafioMantenha a remoção consistente
  11. 11
    DesafioCombine contagens com membros distintos
  12. 12
    RecapitulaçãoVerifique uma primeira entrada e uma repetição
3

Compare dois grupos de participantes

9 passos
Use a pertinência a conjuntos, preserve os originais e apresente a diferença correta.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoPergunte quem participou, não quantas visitas houve
  2. 2
    ExemploElimine leituras repetidas
  3. 3
    DesafioPare na primeira entrada repetida
  4. 4
    ExemploMantenha apenas os membros comuns
  5. 5
    ExplicaçãoEscolha a direção da diferença
  6. 6
    DesafioTeste um grupo selecionado
  7. 7
    DicaEscolha uma ordem útil para o relatório
  8. 8
    DesafioFaça um relatório ordenado de ausências
  9. 9
    RecapitulaçãoInterprete o receptor como o grupo inicial
4

Interprete declarações e cópias de coleções

10 passos
Use interfaces, identifique sobrecargas e distinga a estrutura dos objetos compartilhados.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoInterprete os dois lados da declaração
  2. 2
    ExplicaçãoDeclare o que quem chama o método precisa
  3. 3
    ExemploUse um parâmetro mais abrangente para leitura
  4. 4
    DesafioIdentifique a causa do método ausente
  5. 5
    ConexãoEscolha o significado do conteúdo
  6. 6
    ExemploAcompanhe a remoção de inteiros
  7. 7
    DesafioCopie antes de ordenar
  8. 8
    Ideia-chaveDistinga alterações em objetos de alterações na lista
  9. 9
    DesafioPasse a visão correta do mapa
  10. 10
    RecapitulaçãoVerifique tipo, operação e objeto
5

Construa uma classificação que preserve os empates corretos

15 passos
Ordene cadeias de caracteres e objetos, escreva comparações seguras e verifique a pertinência em conjuntos ordenados.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoEscolha o que vem primeiro
  2. 2
    ExemploOrdene a mesma lista
  3. 3
    ExplicaçãoExamine o primeiro caractere diferente
  4. 4
    DesafioUse uma ordem fornecida
  5. 5
    ExplicaçãoDê uma ordem natural a uma classe
  6. 6
    ExemploEvite um falso empate numérico
  7. 7
    DesafioInverta o campo numérico
  8. 8
    ExemploDesfaça apenas empates reais
  9. 9
    ExemploAcompanhe a classificação
  10. 10
    DesafioVeja o que um conjunto em árvore mantém
  11. 11
    Ideia-chaveFaça a ordenação corresponder à identidade
  12. 12
    ConexãoVerifique a chave de um mapa ordenado
  13. 13
    DesafioMantenha todos os resultados em uma lista classificada
  14. 14
    DicaFaça a regra funcionar para três elementos
  15. 15
    RecapitulaçãoVerifique uma comparação em dois contextos
6

Escolha estruturas para uma lista de alunos de cursos

10 passos
Combine consulta, pertinência, ordenação e custo sem buscas repetidas.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoListe as perguntas que o programa faz
  2. 2
    ExemploObserve a busca dentro do laço
  3. 3
    ExplicaçãoPrepare a verificação de pertinência uma única vez
  4. 4
    DesafioCompare entradas em crescimento
  5. 5
    ExemploMantenha registros de matrícula repetidos
  6. 6
    ExplicaçãoEscolha a ordem externa e a interna
  7. 7
    DesafioCorrija a regra errada para duplicatas
  8. 8
    DicaConsidere o custo da ordem necessária
  9. 9
    DesafioCombine o projeto final
  10. 10
    RecapitulaçãoEscolha o comportamento antes de medir a velocidade

Questões de HashMaps e coleções em Java

50 Questões de Prática em 5 conjuntos

Conjunto 1: Use interfaces e ordene dados10 Questões de Prática

Questão 1 de 10

Em Set<String> codes = new HashSet<>();, qual é o tipo declarado de codes?
  1. HashSet<String>
  2. String
  3. Collection<HashSet>
  4. Set<String>
Mostrar respostaOcultar resposta
Resposta: D
O tipo antes do nome da variável é Set<String>, portanto chamadas por meio de codes são verificadas em relação a essa interface. O lado direito constrói um objeto HashSet. Confundir a classe do objeto com o tipo declarado da variável pode ocultar por que um método específico da classe não está disponível por meio de uma variável de interface.

Questão 2 de 10

O que significa um valor positivo retornado por a.compareTo(b)?
  1. a vem antes de b nessa ordem.
  2. a e b estão empatados nessa ordem.
  3. a vem depois de b nessa ordem.
  4. a tem um campo numérico maior.
Mostrar respostaOcultar resposta
Resposta: C
Uma comparação positiva coloca a depois de b; uma comparação negativa o coloca antes de b, e zero indica empate. A magnitude não mede uma distância numérica obrigatória. Um resultado de 5 pode expressar a mesma ordenação que um resultado de 1, dependendo da implementação da comparação.

Questão 3 de 10

Uma List<Integer> mutável começa como [4, 8, 12]. Ela executa remove(1). O que permanece?
  1. [4, 12]
  2. [8, 12]
  3. [4, 8]
  4. [4, 8, 12]
Mostrar respostaOcultar resposta
Resposta: A
O literal 1 é um int, portanto a sobrecarga de remoção por índice exclui o elemento na posição 1, que é 8. O resultado é [4, 12]. Remover o valor numérico 1 exigiria a sobrecarga de remoção por objeto, e esse valor não está presente na lista.

Questão 4 de 10

Qual é a ordem natural das cadeias de caracteres "zebra", "Apron", "18", "3", "ant"?
  1. [“3”, “18”, “ant”, “Apron”, “zebra”]
  2. [“18”, “3”, “Apron”, “ant”, “zebra”]
  3. [“18”, “3”, “ant”, “Apron”, “zebra”]
  4. [“Apron”, “ant”, “zebra”, “18”, “3”]
Mostrar respostaOcultar resposta
Resposta: B
A comparação de cadeias começa no primeiro caractere diferente, portanto “18” vem antes de “3” sem conversão numérica. Para esses caracteres, algarismos vêm antes de letras maiúsculas, que vêm antes de minúsculas. A ordem alfabética sem distinção entre maiúsculas e minúsculas colocaria ant antes de Apron, mas essa é uma regra de comparação diferente.

Questão 5 de 10

Um método somente de leitura aceita Collection<String>. Quem o chama tem Map<String, String> labels e quer que o método processe cada valor de rótulo. O que deve ser passado?
  1. labels.values()
  2. labels
  3. labels.entrySet()
  4. labels.keySet().iterator()
Mostrar respostaOcultar resposta
Resposta: A
A visão de valores é uma Collection<String> que contém os valores dos rótulos. O próprio mapa não é uma Collection, e seu conjunto de entradas contém entradas em vez de cadeias de caracteres. Passar o iterador forneceria um objeto de percurso em vez do tipo de coleção exigido pelo parâmetro.

Questão 6 de 10

Uma comparação de preços retorna (int) (this.price - other.price). O que dá errado para os preços 6,8 e 6,3?
  1. Ela sempre coloca 6,8 antes de 6,3.
  2. Ela causa estouro do intervalo de int.
  3. Ela retorna zero para preços diferentes.
  4. Ela transforma os dois preços armazenados em inteiros.
Mostrar respostaOcultar resposta
Resposta: C
A diferença decimal é menor que 1, portanto convertê-la explicitamente para int descarta sua parte fracionária e produz zero. Isso indica incorretamente um empate. Trata-se de truncamento, não de estouro de inteiro, e os campos de preço armazenados não são alterados; Double.compare preserva a ordem correta.

Questão 7 de 10

Os resultados devem ser ordenados por pontos, do maior para o menor, e depois por nome, de A a Z. A comparação principal é diferente de zero. O que compareTo deve fazer em seguida?
  1. Comparar os nomes e retorná-lo.
  2. Retornar zero para manter a ordem de entrada.
  3. Retornar uma comparação de nomes negada.
  4. Retornar essa comparação principal.
Mostrar respostaOcultar resposta
Resposta: D
Um resultado principal diferente de zero já decide qual pontuação vem primeiro. Retorná-lo preserva a prioridade da pontuação; a comparação de nomes cabe apenas no caso de pontuações empatadas. Comparar os nomes mesmo assim poderia permitir que um nome anterior em ordem alfabética superasse uma pontuação maior e implementaria uma classificação diferente.

Questão 8 de 10

Uma lista modificável contém um objeto Ticket mutável. Um segundo ArrayList é copiado dela. O programa altera o rótulo do ticket por meio da cópia e depois limpa a cópia. O que a lista original contém?
  1. Uma lista vazia, sem nenhum ticket.
  2. O mesmo ticket com seu rótulo alterado.
  3. Um ticket separado com seu rótulo original.
  4. O mesmo ticket com seu rótulo original.
Mostrar respostaOcultar resposta
Resposta: B
A cópia superficial compartilha inicialmente a referência ao Ticket, portanto a alteração do rótulo afeta o objeto visível pela lista original. Limpar a cópia remove apenas a referência da própria cópia. Isso não duplica os objetos armazenados nem restaura seus campos anteriores.

Questão 9 de 10

Uma classe compara por nível decrescente e depois por código crescente. Os registros são Delta 2, Beta 4, Alpha 2 e Echo 4. Qual é a ordem resultante?
  1. Echo 4, Beta 4, Delta 2, Alpha 2.
  2. Alpha 2, Beta 4, Delta 2, Echo 4.
  3. Beta 4, Echo 4, Alpha 2, Delta 2.
  4. Alpha 2, Delta 2, Beta 4, Echo 4.
Mostrar respostaOcultar resposta
Resposta: C
O nível coloca os dois registros de nível 4 antes dos dois de nível 2. Dentro desses níveis empatados, os códigos crescentes colocam Beta antes de Echo e Alpha antes de Delta. Inverter todo um resultado crescente por nível e código também inverteria os códigos nos empates, colocando Echo antes de Beta, em vez de seguir os sentidos solicitados.

Questão 10 de 10

Reading.equals usa o ID da estação e a temperatura, mas sua comparação natural usa apenas a temperatura. Um TreeSet padrão recebe A com 16, B com 16 e depois C com 12. Qual é seu tamanho e quais IDs são mantidos?
  1. Tamanho 2; IDs C e A.
  2. Tamanho 3; IDs C, A e B.
  3. Tamanho 2; IDs C e B.
  4. Tamanho 1; apenas o ID C.
Mostrar respostaOcultar resposta
Resposta: A
A é inserido primeiro com temperatura 16. B tem comparação igual a zero com A, portanto sua adição é rejeitada; C ocupa uma posição separada de temperatura menor. O conjunto em árvore mantém C e A em ordem de temperatura. A distinção por estação feita pela igualdade não controla a detecção de duplicatas quando a comparação omite esse campo.
Conjunto 2: Leia e atualize mapas de forma confiável10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um HashMap<String, Integer> vazio recebe put("brush", 5) e depois put("brush", 14). Qual é seu tamanho e qual é o valor de "brush"?
  1. Tamanho 2; valor 14.
  2. Tamanho 1; valor 14.
  3. Tamanho 1; valor 19.
  4. Tamanho 2; valor 5.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um mapa de quantidades não nulas não tem a chave "tray". O que acontece quando int n = map.get("tray"); é executado?
  1. Armazena 0 em n e continua.
  2. Lança ClassCastException.
  3. Insere "tray" com valor 0.
  4. Lança NullPointerException.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um laço deve ler cada ID de dispositivo junto com seu estado em um mapa. Qual visão fornece ambos em um único elemento do laço?
  1. entrySet()
  2. keySet()
  3. values()
  4. map.keySet().toArray()
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Dois objetos separados são iguais segundo um método equals correto. Como devem ser seus códigos de dispersão?
  1. Valores inteiros diferentes.
  2. Suas quantidades de campos.
  3. O mesmo valor inteiro.
  4. Seus endereços de memória.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um mapa contém "beam" → 9. O programa executa Integer old = map.put("beam", 13); e depois Integer removed = map.remove("beam");. Quais são old, removed e o tamanho final?
  1. 13, 13 e 0.
  2. 9, 9 e 0.
  3. 9, 13 e 1.
  4. 9, 13 e 0.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um laço de limpeza de estoque percorre entrySet() e deve excluir cada entrada com valor zero. Como ele deve remover a entrada durante o percurso?
  1. Usar o iterador desse percurso e chamar seu remove() depois de next().
  2. Usar um laço for-each e chamar o remove() do mapa para cada chave com valor zero.
  3. Usar um laço sobre entradas e substituir cada valor zero por null.
  4. Usar um laço sobre valores e remover diretamente de keySet() cada chave com valor zero.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Uma classe Cell define equals(Cell other) e um hashCode baseado em campos. Células separadas com campos iguais não correspondem como chaves de HashMap. Que alteração de método corrige o erro de igualdade?
  1. Manter equals(Cell other) e retornar um código de dispersão constante.
  2. Sobrescrever equals(Object other) com as mesmas comparações de campos.
  3. Substituir o método de igualdade por um toString() baseado nos campos.
  4. Adicionar compareTo(Cell other) sem alterar os métodos de igualdade.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma busca em HashMap registra uma chave apenas quando sua pontuação é estritamente maior que a melhor pontuação até o momento. Duas chaves empatam na maior pontuação. Que resultado o programa pode garantir?
  1. Uma das chaves empatadas, sem ordem de desempate garantida.
  2. A chave empatada inserida primeiro no mapa.
  3. A chave empatada com o primeiro nome em ordem alfabética.
  4. A chave empatada inserida mais recentemente no mapa.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um mapa começa com "ink" → 4 e "paper" → 0. keys é um novo ArrayList copiado de seu conjunto de chaves. O programa remove "ink" de keys, remove "paper" pela visão do conjunto de chaves do mapa e depois dobra todos os valores restantes do mapa. O que resta no mapa?
  1. Apenas "paper" → 0.
  2. Nenhuma associação.
  3. Apenas "ink" → 8.
  4. "ink" → 8 e "paper" → 0.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

A igualdade e o cálculo de hash de Location usam uma coordenada mutável. Uma chave é armazenada e sua coordenada é alterada enquanto ela está armazenada; agora sua associação não é encontrada na consulta. Que sequência de atualização o projeto deve usar para evitar essa falha?
  1. Alterar a coordenada; obter pela nova coordenada; inserir novamente.
  2. Remover antes da alteração; alterar a coordenada; inserir novamente.
  3. Alterar a coordenada; substituir equals; obter pela coordenada anterior.
  4. Manter uma segunda referência; alterar a coordenada; consultar com ela.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Construa contagens e compare grupos10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

A sequência é [12, 7, 4, 12, 7]. Um laço para no primeiro !seen.add(n). Qual número é informado?
  1. 7
  2. 4
  3. 12
  4. Nenhum número.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

O mesmo objeto Device é armazenado em uma lista e em um mapa por ID. Ele é recuperado do mapa e depois seu campo de estado é alterado. Qual estado a referência armazenada na lista apresenta?
  1. O estado alterado no mesmo objeto.
  2. O estado original em um objeto copiado separado.
  3. Null até a entrada da lista ser substituída.
  4. O estado alterado apenas após um segundo put no mapa.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

A = {2, 5, 8, 11} e B = {5, 11, 14}. Um conjunto copiado C começa com A e depois executa C.removeAll(B). O que C contém?
  1. {5, 11}
  2. {14}
  3. {2, 5, 8, 11, 14}
  4. {2, 8}
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um mapa de frequências registra "north" → 4, "south" → 2 e "west" → 3. Quantas chaves distintas ele contém?
  1. 9
  2. 4
  3. 3
  4. 2
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um HashSet já contém "cedar". O que outra chamada a add("cedar") retorna?
  1. false
  2. true
  3. null
  4. A cadeia armazenada.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um curso deve listar cada participante apenas uma vez, mesmo quando chegam registros de inscrição duplicados. Qual regra de coleção interna é adequada a cada grupo de curso?
  1. Uma lista de IDs de participantes.
  2. Uma contagem inteira de registros.
  3. Um ID de participante como cadeia de caracteres.
  4. Um conjunto de IDs de participantes.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

O laço processa "red", "gold", "red", "blue", "gold", "red" usando counts.put(word, counts.getOrDefault(word, 0) + 1). Quais são a contagem de red e o tamanho do mapa?
  1. Contagem de red 1; tamanho 3.
  2. Contagem de red 3; tamanho 3.
  3. Contagem de red 3; tamanho 6.
  4. Contagem de red 6; tamanho 3.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Dentro de um laço de agrupamento, cada entrada executa groups.put(team, new ArrayList<>()); seguido de groups.get(team).add(name);. Uma equipe recebe Omar, Pia e depois Ren. O que permanece sob essa equipe?
  1. [Omar, Pia, Ren]
  2. [Ren]
  3. [Omar]
  4. Uma lista vazia.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um mesmo ArrayList é armazenado sob "Morning" e "Evening". O programa adiciona "Lee" por Morning, depois substitui a associação de Evening por uma nova lista e adiciona "Jo" por Evening. Quais são os grupos finais?
  1. Morning [Lee]; Evening [Jo].
  2. Morning [Lee, Jo]; Evening [Lee, Jo].
  3. Morning []; Evening [Lee, Jo].
  4. Morning [Jo]; Evening [Jo].
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

A = {1, 3, 6} e B = {3, 6, 9}. C é copiado de A e executa retainAll(B). D é copiado de B e executa removeAll(C). Quais são D e o resultado de A.containsAll(C)?
  1. D = {1}; o resultado é verdadeiro.
  2. D = {9}; o resultado é falso.
  3. D = {3, 6, 9}; o resultado é falso.
  4. D = {9}; o resultado é verdadeiro.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Identifique o comportamento de coleções10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um programa armazena a precipitação em milímetros em uma posição para cada um dos doze meses. Ele precisa de um número fixo de posições para valores numéricos primitivos. Qual estrutura atende diretamente à necessidade?
  1. Um Set<Double> de medições.
  2. Um vetor double[12].
  3. Um Map<Double, String> de meses.
  4. Um HashSet<Integer> de números de meses.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um HashMap contém a chave "pending" explicitamente associada a null. O que getOrDefault("pending", 20) retorna?
  1. 20
  2. 0
  3. null
  4. Uma exceção da própria consulta.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

O que acontece quando Set.of("draft", "final", "draft") é avaliado?
  1. Lança IllegalArgumentException.
  2. Retorna um conjunto com dois elementos.
  3. Retorna uma lista com três elementos.
  4. Lança UnsupportedOperationException.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um índice de membros usa nomes de exibição como chaves. Dois membros diferentes chamados "Ari Chen" são inseridos, e o primeiro não pode mais ser recuperado por esse nome. Qual projeto preserva diretamente ambos para consulta individual?
  1. Manter a chave de nome, mas usar TreeMap.
  2. Manter a chave de nome em um LinkedHashMap.
  3. Chamar put novamente com o mesmo nome.
  4. Indexar pelo ID único de cada membro.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma lista mutável contém atualmente [10, 2, 7]. Após Collections.reverse(list), qual é seu conteúdo?
  1. [10, 7, 2]
  2. [2, 7, 10]
  3. [7, 10, 2]
  4. [7, 2, 10]
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um programa verifica repetidamente se IDs aparecem em um ArrayList grande e não precisa das posições para essas verificações. Que alteração evita repetir o trabalho de busca completa?
  1. Construir um novo HashSet dentro do laço de consulta.
  2. Copiar o ArrayList uma vez para um LinkedList.
  3. Construir um HashSet antes do laço de consultas.
  4. Ordenar um novo ArrayList para cada consulta.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um mapa de agrupamento não tem a chave "Support". O programa avalia List<String> result = groups.getOrDefault("Support", new ArrayList<>()); e depois adiciona "Nia" a result. O que uma chamada posterior a groups.get("Support") retorna?
  1. null, pois o valor padrão nunca foi inserido.
  2. Uma lista contendo Nia, pois o valor padrão se tornou o grupo.
  3. Uma lista vazia, pois o valor padrão foi armazenado antes da adição.
  4. Uma exceção, pois uma lista padrão não armazenada não pode ser modificada.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

A igualdade de ScoreKey usa equipe e pontos; sua comparação natural usa apenas pontos. Um TreeMap padrão recebe a chave East-30 com valor "old", West-30 com valor "new" e depois North-18 com valor "low". Qual é seu tamanho e qual valor é encontrado usando East-30?
  1. Tamanho 3; o valor é "old".
  2. Tamanho 2; o valor é "new".
  3. Tamanho 2; o valor é "old".
  4. Tamanho 1; o valor é "low".
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

A = {4, 7, 10} e B = {7, 10, 13}. Uma cópia U executa primeiro addAll(B) e depois removeAll(A). Qual é U e algum dos originais mudou?
  1. U = {4}; ambos os originais permanecem inalterados.
  2. U = {4, 13}; apenas A foi alterado.
  3. U = {7, 10}; apenas B foi alterado.
  4. U = {13}; ambos os originais permanecem inalterados.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um relatório precisa de cursos em ordem alfabética e dos IDs distintos de membros de cada curso na ordem da primeira inscrição. Quais implementações externas e internas funcionam juntas?
  1. TreeMap por fora; LinkedHashSet por dentro.
  2. LinkedHashMap por fora; TreeSet por dentro.
  3. TreeMap por fora; ArrayList por dentro.
  4. HashMap por fora; LinkedHashSet por dentro.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 5: Combine consulta, agrupamento e ordem10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um mapa contém duas chaves diferentes, cada uma associada a 6. Qual total a soma de map.values() produz?
  1. 12
  2. 6
  3. 2
  4. 1
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

O que determina a igualdade entre um ArrayList e um LinkedList que contêm os mesmos valores de elementos?
  1. Os valores devem aparecer na mesma ordem.
  2. As listas devem ter a mesma classe concreta.
  3. Apenas o número de valores distintos deve coincidir.
  4. As referências aos elementos devem ser todas idênticas.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um mapa de totais inicialmente vazio processa reparos 4,25, entrega 2,50 e reparos 3,75 usando uma soma com zero como valor padrão. Qual é seu tamanho e qual é o total de reparos?
  1. Tamanho 3; total de reparos 8,00.
  2. Tamanho 2; total de reparos 3,75.
  3. Tamanho 2; total de reparos 10,50.
  4. Tamanho 2; total de reparos 8,00.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Uma classe personalizada com igualdade correta retorna o mesmo código de dispersão para todas as instâncias. O que acontece com a correção e o desempenho de consulta do HashSet?
  1. Todos os valores se tornam um único elemento, acelerando a consulta.
  2. Valores diferentes continuam válidos, mas consultas podem ficar mais lentas.
  3. Valores distintos continuam válidos, com consulta em tempo constante garantida.
  4. Toda inserção falha na compilação porque códigos de dispersão se repetem.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma classe de temperatura deve comparar dois campos double em ordem crescente sem falsos empates causados por uma conversão explícita. Qual expressão de retorno é adequada?
  1. (int) (this.value - other.value)
  2. Double.compare(other.value, this.value)
  3. Double.compare(this.value, other.value)
  4. Integer.compare((int) this.value, (int) other.value)
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um catálogo mantém os mesmos objetos Item em um índice por ID e em um índice que associa categorias a listas. A categoria de um item muda de Cables para Adapters. Alterar apenas seu campo de categoria o deixa na lista Cables. Qual atualização mantém os índices consistentes?
  1. Substituí-lo no mapa por ID; deixar as duas listas de categorias como estão.
  2. Mudar o mapa por ID para TreeMap; manter as duas listas de categorias como estão.
  3. Mover sua referência entre as listas de categorias; manter sua associação por ID.
  4. Copiar o item sob a categoria antiga; remover sua associação por ID.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Uma classe de jogador define igualdade por nome e pontuação e compara por pontuação decrescente e depois por nome crescente. Um TreeSet padrão recebe Mira 9, Axel 12, Mira 9 e Bo 9 como objetos separados. Quais membros resultam em ordem?
  1. Axel 12, Mira 9, Bo 9.
  2. Axel 12, Mira 9, Mira 9, Bo 9.
  3. Bo 9, Mira 9, Axel 12.
  4. Axel 12, Bo 9, Mira 9.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Um programa tem uma lista de valores autorizados e uma lista de consultas. Os dois tamanhos dobram. Compare buscas completas repetidas na lista com a construção de um HashSet de valores autorizados seguida de consultas a ele, com hash adequado. Como cresce o trabalho total de cada abordagem?
  1. Ambos os totais podem quadruplicar porque as duas entradas têm o dobro de valores.
  2. O trabalho de busca na lista pode quadruplicar; a construção e consulta do conjunto aproximadamente dobram.
  3. O trabalho de busca na lista aproximadamente dobra; a construção e consulta do conjunto permanecem constantes.
  4. Ambos os totais permanecem constantes porque cada abordagem usa uma chamada de método por consulta.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um mapa agrupa notas por projeto. Dois projetos devem manter listas independentes, notas repetidas e ordem de chegada. O código existente cria um ArrayList compartilhado, coloca-o sob cada nova chave e adiciona notas por meio de get. Qual correção completa preserva os requisitos?
  1. Manter o ArrayList compartilhado, mas substituir cada get por getOrDefault usando a mesma lista.
  2. Criar um novo ArrayList para cada nova chave e acrescentar notas por sua referência armazenada.
  3. Criar um novo HashSet para cada nova chave e adicionar notas por sua referência armazenada.
  4. Criar um novo ArrayList vazio para o projeto a cada entrada e acrescentar a nota atual.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um sistema de documentos precisa de marcadores únicos na ordem em que foram vistos pela primeira vez, consulta direta de objetos por ID único de documento e um histórico ordenado separado que mantenha visitas repetidas. Quais estruturas atendem às três necessidades?
  1. TreeSet para marcadores; List para consulta por ID; HashSet para histórico.
  2. HashSet para marcadores; Map para consulta por ID; TreeSet para histórico.
  3. LinkedHashSet para marcadores; Set para consulta por ID; Map por ID de documento para histórico.
  4. LinkedHashSet para marcadores; Map para consulta por ID; List para histórico.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

70 Termos-Chave, cada um com sua definição

A

Agrupamento
O agrupamento reúne itens com uma propriedade comum sob uma chave de mapa, usando uma lista ou um conjunto como valor para armazenar cada grupo.
Uma chave de curso pode levar a uma lista de alunos, enquanto uma chave de primeira letra pode levar a palavras correspondentes.

C

Chave mutável
Uma chave mutável tem dados que podem mudar; alterar campos usados em sua igualdade ou em seu código de dispersão enquanto ela está armazenada pode comprometer a consulta no mapa.
Uma chave de coordenadas é mais segura com campos final do que com métodos modificadores que podem alterar sua identidade enquanto está armazenada.
Classe empacotadora
Uma classe empacotadora fornece um tipo de objeto para um valor primitivo, permitindo que números e outros dados primitivos sejam usados como argumentos de tipo em coleções.
Um mapa de quantidades usa Integer como tipo de valor porque int não pode aparecer como argumento de tipo genérico.
Classe HashMap
Um HashMap é um mapa modificável de Java que armazena chaves únicas com valores associados e não garante uma ordem específica de iteração.
Um HashMap<String, Integer> pode consultar a contagem atual de um produto sem usar uma posição em uma lista.
Classe HashSet
Um HashSet é um conjunto modificável de Java com operações básicas em tempo constante em média, com hash adequado, e sem ordem de iteração garantida.
Um HashSet<String> pode acompanhar nomes já processados enquanto um programa lê uma sequência de entrada maior.
Classe LinkedHashMap
Um LinkedHashMap é um mapa cuja forma comum, ordenada por inserção, visita as chaves em ordem de inserção e mantém as operações usuais de mapa.
Substituir um preço armazenado mantém a posição desse produto em um LinkedHashMap ordenado por inserção.
Classe LinkedHashSet
Um LinkedHashSet armazena elementos distintos preservando sua ordem de inserção, inclusive a ordem das primeiras ocorrências quando copiado de uma lista.
Uma lista de marcadores copiada para um LinkedHashSet perde as repetições, mantendo a ordem em que os marcadores apareceram pela primeira vez.
Classe TreeMap
Um TreeMap mantém associações ordenadas por suas chaves e usa a comparação de chaves para identificar uma associação existente durante uma consulta ou substituição.
Um relatório de contagem de palavras em ordem alfabética pode usar um mapa em árvore cuja menor chave está disponível por meio de firstKey().
Classe TreeSet
Um TreeSet mantém elementos ordenados e usa seu resultado de comparação para decidir se um elemento já está presente no conjunto.
Uma comparação de membros apenas por altura faz com que dois membros diferentes com alturas iguais disputem uma única posição no conjunto.
Coleção aninhada
Uma coleção aninhada armazena coleções dentro de outra estrutura, permitindo que chaves externas e membros internos sigam regras separadas.
Um mapa ordenado de cursos pode conter listas de alunos em ordem de inserção sem ordenar os próprios alunos.
Coleção não modificável
Uma coleção não modificável rejeita alterações estruturais ou substituições por meio de sua API, embora os objetos que ela contém ainda possam ser mutáveis.
Uma lista criada com List.of deve ser copiada antes da ordenação, mas um objeto mutável armazenado não é congelado por essa lista.
Comparador
Um comparador é um objeto que fornece uma regra de comparação que pode ser diferente da ordem natural de uma classe, como ordem inversa ou sem distinção entre maiúsculas e minúsculas.
String.CASE_INSENSITIVE_ORDER ordena uma lista sem alterar as letras maiúsculas e minúsculas armazenadas em cada cadeia.
Conjunto
Um conjunto é uma coleção de elementos distintos que fornece operações de pertinência sem as posições indexadas de uma lista.
Um conjunto de cidades visitadas mantém uma entrada para cada cidade, mesmo quando um viajante retorna várias vezes.
Consistência com equals
A consistência com equals significa que a comparação retorna zero exatamente quando a igualdade retorna verdadeiro, de modo que ambas as regras identificam os mesmos valores.
Um conjunto em árvore precisa que a comparação de membros distinga as mesmas identidades que a regra de igualdade dos membros.
Consulta por chave
Uma consulta por chave encontra um valor por meio de um identificador separado, tornando um mapa útil quando buscas repetidas precisariam examinar campos de objetos.
Um mapa por código de produto responde diretamente a consultas de preço, enquanto uma lista exigiria uma busca pelo código correspondente.
Contrato do código de dispersão
O contrato do código de dispersão exige que objetos iguais segundo equals retornem códigos de dispersão iguais, permitindo colisões para objetos diferentes.
Chaves de coordenadas usam os mesmos campos x e y tanto no teste de igualdade quanto no método de código de dispersão.
Cópia superficial
Uma cópia superficial cria uma estrutura de coleção separada que contém as mesmas referências aos elementos, em vez de duplicar os objetos armazenados.
Remover um livro de uma lista copiada deixa a lista original intacta, mas ambas ainda podem referenciar o mesmo livro.
Critério de desempate
Um critério de desempate é uma comparação secundária usada apenas quando campos de comparação anteriores empatam, preservando sua prioridade na ordem geral.
Uma comparação de filmes por ano e depois por título consulta os títulos apenas para filmes lançados no mesmo ano.
Custo de preparação
Um custo de preparação é o trabalho necessário para construir uma estrutura de apoio antes que operações posteriores possam se beneficiar dela.
Um conjunto de pertinência deve ser construído uma vez antes de muitas verificações, incluindo sua construção no trabalho total.

D

Desempacotamento
O desempacotamento é a conversão automática, feita por Java, de um objeto empacotador para um valor primitivo; tentar fazê-la com null lança uma exceção.
Atribuir a um int o resultado de uma consulta Integer a uma chave ausente falha porque o null retornado não pode ser desempacotado.
Diferença de conjuntos
Uma diferença de conjuntos contém elementos do primeiro conjunto que estão ausentes do segundo, portanto inverter os conjuntos pode alterar o resultado.
Remover os participantes de terça-feira de uma cópia de segunda-feira encontra quem participou apenas na segunda-feira, não apenas na terça-feira.

E

Empacotamento automático
O empacotamento automático é a conversão automática, feita por Java, de um valor primitivo para o objeto empacotador correspondente quando um objeto é necessário.
Inserir o literal 12 em um mapa de valores Integer empacota automaticamente esse número para armazenamento.
Encapsulamento
O encapsulamento mantém dados dentro de uma classe e disponibiliza métodos controlados, permitindo que a classe mantenha regras de atualização e consulta.
Uma classe de biblioteca pode manter seus índices privados para que seu método addBook os atualize em conjunto, em vez de quem chama alterá-los.
Escolha da coleção
A escolha da coleção relaciona os requisitos de posições, duplicatas, consulta por chave e ordem a uma interface e a uma implementação adequada.
Um relatório de contagens em ordem alfabética e uma playlist ordenada precisam de estruturas diferentes porque preservam informações diferentes.
Estouro de inteiro
O estouro de inteiro ocorre quando um resultado aritmético excede o intervalo de int e volta ao outro extremo, o que pode dar o sinal errado a comparações baseadas em subtração.
Comparar campos int extremos com Integer.compare evita a inversão de sinal que a subtração pode causar.

I

Identificador único
Um identificador único distingue cada objeto nos dados indexados, impedindo que registros separados disputem a mesma chave de mapa.
Um ID de membro mantém duas pessoas com o mesmo nome de exibição em entradas separadas de um índice de membros.
Igualdade de conteúdo
A igualdade de conteúdo trata objetos separados como iguais quando os dados escolhidos correspondem, usando uma sobrescrita adequada de equals(Object).
Duas chaves de coordenadas criadas separadamente podem encontrar o mesmo rótulo quando sua igualdade compara ambas as coordenadas.
Igualdade por identidade
A igualdade por identidade considera objetos iguais apenas quando são a mesma instância; essa é a igualdade herdada de Object.
Sem sobrescritas, um ponto recém-construído não corresponde a um ponto armazenado com coordenadas idênticas.
Implementação
Uma implementação é uma classe concreta que fornece as operações de uma interface e determina o comportamento do objeto criado.
HashMap e TreeMap implementam Map, mas oferecem garantias diferentes sobre a ordem das chaves.
Interface
Uma interface declara operações fornecidas pelas classes que a implementam, permitindo que uma variável ou um parâmetro indique as capacidades de que precisa.
Um método que aceita List<String> pode receber um ArrayList ou um LinkedList sem alterar sua assinatura.
Interface Collection
Collection é a interface comum de Java para grupos de elementos, estendida por List e Set, mas separada da interface Map.
Um método somente de leitura que conta palavras pode aceitar uma Collection<String> e percorrer uma lista ou um conjunto.
Interface Comparable
Comparable é a interface de Java por meio da qual uma classe define sua ordem natural implementando um método compareTo com tipo específico.
Uma classe de membro pode implementar Comparable<Member> para que a ordenação de listas ordene suas instâncias por altura.
Interface Map.Entry
Uma Map.Entry representa uma associação chave–valor e dá acesso à chave e ao valor juntos durante o percurso de um mapa.
Um laço sobre entradas pode exibir o nome e a pontuação de um jogador sem consultar novamente a pontuação pelo nome.
Interseção
A interseção de dois conjuntos contém apenas os elementos compartilhados por ambos; retainAll remove do receptor os valores não compartilhados.
Manter apenas os nomes de terça-feira em uma cópia do conjunto de segunda-feira encontra as pessoas que participaram nos dois dias.
Item distinto
Um item distinto é um valor considerado diferente segundo a regra de correspondência da coleção, independentemente de quantas vezes ele ocorre.
Um mapa de frequências para "sun rain sun" contém duas chaves de palavras distintas, mas registra três ocorrências.
Iterador
Um iterador acompanha um percurso por uma coleção e fornece métodos para verificar e recuperar o próximo elemento.
Um laço de limpeza de estoque usa hasNext(), next() e o remove() do iterador para excluir quantidades zero.

Í

Índice
Um índice é um mapa de uma chave de identificação para um objeto, permitindo consultas por essa chave sem pesquisar repetidamente uma lista de objetos.
O índice por ISBN de uma biblioteca pode retornar o mesmo objeto de livro que também aparece em sua lista de todos os livros.

L

Lista
Uma List armazena elementos em uma sequência indexada a partir de zero, permite duplicatas e compara a igualdade usando a ordem completa dos elementos.
Uma playlist usa posições de lista para manter duas ocorrências da mesma música em pontos diferentes da sequência.
Listas paralelas
Listas paralelas armazenam campos associados em índices correspondentes de listas separadas, fazendo com que a relação dependa de alterações estruturais coordenadas.
Remover o nome de uma pessoa sem remover o número no mesmo índice desalinha as entradas seguintes da agenda telefônica.

M

Mapa
Um Map associa chaves únicas a valores, permitindo valores repetidos enquanto cada chave tem no máximo um valor associado por vez.
Dois produtos podem estar associados ao preço 3,50 sem violar a exigência de que suas chaves sejam únicas.
Método compareTo
O método compareTo retorna um inteiro negativo, zero ou um inteiro positivo para colocar este objeto antes de outro, empatado com ele ou depois dele.
Um resultado de -8 coloca o objeto à esquerda antes do objeto à direita, assim como um resultado de -1.
Método getOrDefault
O método getOrDefault retorna o valor associado a uma chave ou o valor padrão fornecido quando não existe associação para essa chave.
Ler uma contagem ausente com zero como valor padrão fornece 0 sem criar uma nova entrada no mapa de contagens.
Método putIfAbsent
O método putIfAbsent armazena um valor quando uma chave não tem associação com valor não nulo e, caso contrário, mantém o valor já associado à chave.
Antes de adicionar um item agrupado, putIfAbsent pode garantir que sua chave tenha uma lista sem substituir uma lista existente.
Modificação estrutural
Uma modificação estrutural altera o conjunto de chaves de um mapa, como quando uma nova associação é adicionada ou uma associação existente é removida.
Substituir a quantidade de uma chave já presente altera seu valor sem modificar estruturalmente o mapa.

N

Normalização de chaves
A normalização de chaves aplica uma regra consistente de limpeza antes do armazenamento e da consulta para que formas equivalentes de entrada usem a mesma chave de mapa.
Um contador de palavras pode converter unidades de entrada para minúsculas e remover a pontuação antes de adicionar cada ocorrência ao mapa.

O

Ocorrência duplicada na entrada
Uma ocorrência duplicada na entrada é uma ocorrência cujo valor igual já foi visto; um conjunto de valores vistos a detecta quando add retorna falso.
Na sequência 6, 9, 2, 9, 6, o segundo 9 é a primeira entrada que repete um valor anterior.
Ordem de iteração
A ordem de iteração é a sequência em que um percurso visita elementos ou entradas; algumas implementações garantem uma ordem, e outras não.
Uma busca de pontuações empatadas precisa de uma regra explícita de desempate se seu resultado deve ser independente do percurso do HashMap.
Ordem natural
Uma ordem natural é a comparação padrão fornecida por uma classe, como a ordem numérica crescente ou a ordem de cadeias baseada em caracteres.
Ordenar as cadeias "20" e "3" coloca "20" primeiro porque os caracteres iniciais decidem sua ordem.
Ordem por unidades de código dos caracteres
A ordem por unidades de código dos caracteres compara cadeias na primeira unidade de código UTF-16 diferente, colocando primeiro um prefixo correspondente mais curto.
Nos exemplos "7", "Bee" e "ant", a ordem natural de cadeias coloca o algarismo antes das letras.
Ordenação estável
Uma ordenação estável preserva a ordem relativa de entrada dos elementos considerados iguais segundo a comparação usada nessa ordenação.
Dois jogadores empatados por uma comparação apenas de pontuação permanecem em sua ordem relativa anterior após uma ordenação estável de lista.
Ordenação na própria lista
Uma ordenação na própria lista reorganiza a lista fornecida em vez de retornar uma lista ordenada separada para atribuição.
Depois de Collections.sort(values), a variável de lista existente disponibiliza seus elementos na nova ordem.

P

Par chave–valor
Um par chave–valor associa uma chave de identificação a um valor em um mapa, como um código de produto associado a uma quantidade.
Em um mapa de estoque, o par "pen" → 18 associa um nome de produto à quantidade disponível no momento.
Parâmetro de tipo de interface
Um parâmetro de tipo de interface aceita objetos por meio das operações garantidas por uma interface em vez de exigir uma implementação concreta.
Um método de relatório pode aceitar Map<String, Integer> enquanto quem o chama escolhe armazenamento baseado em hash ou em árvore.
Pertinência
A pertinência indica se um valor pertence a um conjunto, como verificado por contains usando a regra de correspondência desse conjunto.
Um programa de verificação de nomes de usuário testa a pertinência antes de aceitar um novo nome em seu conjunto de nomes ocupados.

R

Referência compartilhada
Uma referência compartilhada permite que duas variáveis ou entradas acessem o mesmo objeto, de modo que uma alteração nesse objeto seja visível por qualquer uma das referências.
Duas chaves de curso associadas a um único objeto de lista mostrarão um aluno adicionado por apenas uma dessas chaves.

S

Sintaxe de diamante
A sintaxe de diamante usa sinais de menor e maior vazios em um construtor para que Java possa inferir seus argumentos de tipo a partir da declaração ao redor.
Em HashMap<String, Integer> m = new HashMap<>();, o diamante evita repetir os dois tipos.
Sobrecarga
Uma sobrecarga é um método que compartilha o nome com outro método, mas usa parâmetros diferentes, permitindo que Java escolha uma operação diferente.
Para uma lista de inteiros, remove(1) seleciona a remoção por índice, enquanto remove(Integer.valueOf(1)) seleciona a remoção por valor.
Soma acumulada
Uma soma acumulada é uma quantia que é atualizada adicionando cada nova contribuição à quantia já armazenada.
Um mapa de despesas lê o total anterior da categoria, soma a próxima quantia e armazena o resultado aumentado.
Subconjunto
Um subconjunto tem todos os seus elementos em outro conjunto, que pode conter elementos adicionais; a.containsAll(b) testa se b está contido em a.
Um grupo selecionado é um subconjunto de um conjunto de participantes quando todas as pessoas selecionadas aparecem na lista do evento.

T

Tabela de consulta
Uma tabela de consulta associa códigos ou nomes a dados que um programa recupera ao processar outra tarefa.
Uma calculadora de pedidos lê preços de produtos em uma tabela antes de somar a contribuição de cada produto.
Tabela de frequências
Uma tabela de frequências associa cada item distinto ao seu número de ocorrências, usando geralmente chaves de mapa para itens e valores inteiros para contagens.
Um mapa de contagem de palavras distingue o número de palavras diferentes do número total de ocorrências de palavras.
Tempo constante
O tempo constante descreve um trabalho que permanece aproximadamente independente do número de elementos; operações básicas baseadas em hash têm esse custo em média quando o hash é adequado.
Ler uma posição de um ArrayList não exige percorrer todas as posições anteriores dessa lista.
Tempo linear
O tempo linear descreve um trabalho que pode crescer em proporção ao número de elementos, como quando uma busca pode examinar toda a coleção.
Verificações repetidas de pertinência em uma lista longa podem exigir percursos repetidos dos mesmos nomes armazenados.
Tempo logarítmico
O tempo logarítmico descreve um trabalho que cresce lentamente com o número de elementos, como nos custos garantidos de consultas básicas em mapas e conjuntos em árvore.
Um mapa em árvore mantém as chaves ordenadas e evita um percurso completo a cada consulta comum por chave.
Tipo declarado
O tipo declarado de uma variável determina quais métodos o compilador permite chamar por meio dela, mesmo quando seu objeto tem métodos adicionais.
Um ArrayList armazenado em uma variável List não disponibiliza ensureCapacity por meio dessa variável.
Transitividade
A transitividade exige que uma ordenação coloque a antes de c sempre que colocar a antes de b e b antes de c, mantendo as comparações coerentes.
Comparar campos em uma ordem fixa de prioridade evita um ciclo em que cada um de três objetos precede outro.
Truncamento
O truncamento descarta uma fração decimal quando um valor é convertido explicitamente para int, podendo transformar uma pequena diferença de comparação diferente de zero em zero.
Converter explicitamente para int a diferença entre os preços 2,7 e 2,2 produz um falso empate em vez de uma comparação positiva.

U

União
A união de dois conjuntos contém todos os elementos presentes em qualquer um deles; o addAll de Java a forma alterando o conjunto receptor.
Copiar o conjunto de participantes de segunda-feira e adicionar os de terça-feira fornece todas as pessoas que vieram em pelo menos um dos dias.

V

Vetor
Um vetor armazena um número fixo de elementos indexados de um mesmo tipo e pode conter valores primitivos diretamente, sem argumentos de tipo empacotador.
Um double[12] pode dar a cada mês uma posição para sua medição de precipitação em milímetros.
Visão de coleção
Uma visão de coleção disponibiliza parte de outra estrutura por meio de uma interface de coleção, com alterações vinculadas à estrutura subjacente.
Remover um produto pelo conjunto de chaves do mapa de estoque remove a entrada correspondente do próprio mapa.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar