HashMap y colecciones en Java

Aprende a almacenar y buscar datos por clave con HashMap, contar y agrupar valores y conservar valores únicos con HashSet. Descubre qué garantizan las interfaces List, Set y Map, ordena listas, dota a tus propias clases de un orden natural con Comparable y elige la colección que se ajuste a cada tarea.

PrincipianteUnidad 7 de 11 del curso Curso de Programación orientada a objetos con Java

Lo que aprenderás

  1. Crea mapas hash, añade, lee, actualiza y elimina pares clave-valor, recorre el contenido de un mapa y utiliza tus propias clases como claves que el mapa pueda volver a encontrar.
    • Crea un HashMap e inserta, consulta, actualiza y elimina entradas
      Declara un HashMap con sus tipos de clave y valor, almacena pares con put, léelos con get y gestiona las claves ausentes.
    • Recorre claves, valores y entradas
      Recorre todos los pares de un mapa con keySet, values y entrySet, identifica qué orden puedes esperar y modifica un mapa de forma segura mientras lo recorres.
    • Utiliza tus propios objetos como claves de mapas
      Haz que los objetos de tus propias clases funcionen como claves sobrescribiendo equals y hashCode conjuntamente, y mantén las claves sin cambios mientras estén en un mapa.
  2. Utiliza mapas para contar cuántas veces aparecen elementos, reunir valores relacionados bajo una misma clave y crear tablas de consulta que encuentren objetos rápidamente.
    • Cuenta apariciones y acumula totales por clave
      Construye tablas de frecuencias y sumas acumuladas con el patrón getOrDefault e interpreta correctamente los resultados.
    • Agrupa valores bajo una misma clave utilizando listas y conjuntos como valores
      Construye mapas cuyos valores sean listas o conjuntos, añade elementos al grupo correcto y evita los errores que hacen perder o dañan grupos.
    • Busca objetos y precios rápidamente con un índice basado en un mapa
      Utiliza mapas como tablas de consulta e índices que encuentran objetos mediante una clave única, mantenlos dentro de una clase y conserva la coherencia entre varios índices.
  3. Utiliza HashSet para almacenar valores sin duplicados, comprobar rápidamente la pertenencia y combinar conjuntos mediante unión, intersección y diferencia.
    • Almacena valores únicos y comprueba la pertenencia con HashSet
      Añade, comprueba y elimina valores en un HashSet, utiliza el resultado de add y elimina duplicados de una lista.
    • Combina conjuntos y mantén su orden
      Calcula uniones, intersecciones y diferencias sin alterar los conjuntos originales, compara conjuntos y elige un conjunto ordenado cuando el orden importe.
  4. Declara colecciones mediante sus tipos de interfaz, identifica qué garantiza cada interfaz y utiliza los métodos compartidos que funcionan en distintas implementaciones.
    • Declara variables y parámetros con tipos de interfaz
      Explica qué es un tipo de interfaz, declara colecciones como List, Set o Map y escribe métodos que acepten cualquier implementación.
    • Identifica qué garantizan List, Set y Map
      Compara las garantías de las tres interfaces, reconoce sus principales implementaciones y trabaja con colecciones no modificables creadas con of.
  5. Ordena listas según su orden natural, dota a tus propias clases de un orden natural implementando Comparable y utiliza ese orden en conjuntos y mapas ordenados.
    • Ordena listas de números y cadenas
      Ordena una lista in situ con Collections.sort, predice el orden de las cadenas y ordena en sentido inverso o sin distinguir mayúsculas y minúsculas.
    • Implementa Comparable en tu propia clase
      Dota a una clase de un orden natural implementando Comparable y escribiendo compareTo con comparaciones seguras de números y cadenas.
    • Resuelve empates y utiliza conjuntos y mapas ordenados
      Ordena objetos por varios campos, mantén compareTo consistente con equals y utiliza TreeSet y TreeMap para mantener los datos ordenados.
  6. Compara la rapidez de las operaciones habituales en cada colección y elige el tipo que se ajuste a lo que el programa debe hacer con sus datos.
    • Compara el coste de las operaciones habituales con colecciones
      Estima cómo crece el tiempo de las búsquedas, inserciones y eliminaciones con el tamaño de cada colección, e identifica patrones lentos.
    • Selecciona una colección que se ajuste a la tarea
      Responde a unas preguntas sobre orden, duplicados y búsqueda para elegir entre arreglos, listas, conjuntos y mapas, y combínalos para datos más complejos.

Guía de estudio de HashMap y colecciones en Java

6 capítulos

1

Almacena y busca datos por clave con HashMap

Un código de producto puede llevar directamente a una cantidad en existencias, sin buscar en una lista. Los mapas hacen explícita esa relación, pero utilizarlos bien también implica gestionar claves ausentes, visitar pares de forma segura y definir cuándo dos objetos clave se consideran iguales. Empieza con un pequeño mapa de existencias y sigue cómo cambia su contenido y cómo Java vuelve a encontrar una clave almacenada. Las mismas reglas de igualdad importarán cuando utilices conjuntos.

1.1 Crea un HashMap e inserta, consulta, actualiza y elimina entradas

Un mapa almacena una relación entre cada clave y un valor. En un mapa de existencias, el nombre de un producto es la clave y su cantidad es el valor. Dos productos pueden tener la misma cantidad, pero una clave de producto no puede tener dos entradas separadas.

Crea el mapa
import java.util.HashMap;

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

El primer tipo, String, describe las claves. El segundo, Integer, describe los valores. El diamante <> de la derecha permite que Java infiera esos tipos. Los argumentos de tipo deben ser tipos de referencia: utiliza Integer, Double, Character o Boolean en lugar de int, double, char o boolean. Java empaqueta un int normal cuando lo almacena como Integer y desempaqueta un Integer cuando se necesita un int.

Sigue cada cambio
stock.put("apple", 12);
stock.put("pear", 7);
Integer previous = stock.put("apple", 15);

La primera llamada crea apple=12; la segunda añade pear=7. La tercera encuentra la clave existente "apple" y reemplaza su valor. El mapa tiene ahora dos entradas y previous contiene 12. Un put para una clave sin asociación previa devuelve null.

stock.get("apple") devuelve ahora 15. stock.remove("pear") devuelve 7 y elimina esa entrada. Volver a eliminar "pear" devuelve null. size() cuenta las entradas, isEmpty() comprueba si no hay ninguna y clear() elimina todas las entradas.

Gestiona una clave ausente

stock.get("kiwi") devuelve null y stock.containsKey("kiwi") devuelve false. Esta sentencia se compila, pero falla al ejecutarse:

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

Java intenta desempaquetar null como un int, lo que provoca una NullPointerException. Para un mapa de cantidades no nulas, utiliza un valor predeterminado:

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

Esto proporciona 0 sin añadir "kiwi" al mapa. También puedes comprobar containsKey antes de leer. containsValue(15) pregunta si alguna entrada tiene ese valor; puede recorrer todos los valores, por lo que es diferente de buscar una clave conocida.

Un HashMap también permite una clave null y valores null. Si una clave está asociada explícitamente a null, getOrDefault devuelve ese null almacenado, no el valor predeterminado. containsKey distingue ese caso de una clave ausente. Los mapas de cantidades son más sencillos cuando todas las cantidades almacenadas son números reales.

Compara correctamente claves y valores

Las claves de tipo String distinguen mayúsculas y minúsculas: "apple", "Apple" y "apple " son diferentes. Aplica la misma limpieza antes de almacenar y buscar, por ejemplo, name.trim().toLowerCase(). Limpiar solo una clave de búsqueda no puede corregir claves almacenadas de forma inconsistente.

Compara los valores empaquetados por contenido con equals. Si dos entradas contienen cada una 1000, sus referencias Integer pueden ser distintas, por lo que == puede ser falso aunque sus contenidos numéricos coincidan. Después de comprobar que ambos valores son distintos de null, a.equals(b) compara sus contenidos.

Puntos clave

  • Cada clave única se asocia a un valor; los valores pueden repetirse.
  • put reemplaza un valor existente y devuelve el valor anterior.
  • get devuelve null para una clave ausente; desempaquetarlo provoca una NullPointerException.
  • getOrDefault proporciona un valor predeterminado solo para una clave ausente.
  • Compara las claves de cadena de forma consistente y los valores empaquetados por contenido.

1.2 Recorre claves, valores y entradas

Un mapa puede responder a una búsqueda individual o proporcionar todos sus datos a un bucle. Elige la vista que proporcione las partes que necesita el bucle. Las vistas están vinculadas al mapa, por lo que los cambios realizados a través de ellas también pueden cambiar el mapa.

Elige claves, valores o entradas

Utiliza keySet() para visitar las claves. Una búsqueda dentro de ese bucle puede recuperar cada valor:

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

Utiliza values() cuando las claves no importen. Para las cantidades en existencias apple 15, pear 7 y fig 3:

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

El total pasa a ser 25. Los valores repetidos siguen siendo contribuciones separadas: una vista de valores no es un conjunto.

Una entrada contiene una clave y su valor juntos. Importa java.util.Map y utiliza Map.Entry<K, V> con getKey() y getValue(). Esto evita una segunda búsqueda:

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 y Cai 77, el resultado es Ben con 91. La comprobación best == null también gestiona una primera puntuación igual al menor int posible. Un mapa vacío deja best como null.

Elige el orden de forma explícita

Un HashMap no garantiza ningún orden de iteración. No se puede dar por supuesto el orden de inserción, el orden ordenado ni el orden impreso hoy. Un LinkedHashMap conserva el orden de inserción; un TreeMap visita las claves ordenadas. Si dos puntuaciones empatan, el bucle anterior conserva la primera que visita. Con un HashMap, cualquiera de los nombres empatados podría ganar. Añade una regla de desempate explícita cuando el resultado deba ser predecible.

Elimina entradas mediante el iterador

Llamar a stock.remove(key) dentro de un bucle for-each sobre stock.keySet() cambia las claves que recorre el bucle. Puede provocar una ConcurrentModificationException. La detección no está garantizada; una ejecución sin excepción no hace válido ese patrón.

Utiliza el método de eliminación del propio iterador:

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

Importa java.util.Iterator. Para apple 15, pear 0, fig 0 y kiwi 4, esto elimina pear y fig. Otro método seguro registra las claves en una lista, termina el bucle y después elimina esas claves.

Reemplazar un valor existente no añade ni elimina una clave. Durante un bucle sobre entradas, entry.setValue(entry.getValue() * 2) puede duplicar las cantidades de forma segura. No añadas claves nuevas a través del mapa durante ese bucle.

Distingue una vista de una copia

stock.keySet().remove("apple") elimina la entrada correspondiente del mapa. Una lista independiente creada con new ArrayList<>(stock.keySet()) es una copia de las claves actuales. Ordenar esa lista no cambia el orden del mapa, y eliminar un nombre de la lista no elimina su asociación.

Puntos clave

  • Utiliza keySet, values o entrySet según lo que necesite el bucle.
  • HashMap no garantiza un orden de iteración; resuelve los empates de forma explícita.
  • Utiliza remove de un iterador para eliminar durante el recorrido.
  • Está permitido reemplazar un valor existente durante el recorrido.
  • Las vistas están vinculadas al mapa; una lista de claves copiada es independiente.

1.3 Utiliza tus propios objetos como claves de mapas

Un identificador de producto almacenado como String ya tiene reglas de igualdad útiles. Una clave creada a partir de tu propia clase requiere una decisión: ¿representan dos objetos separados con los mismos datos la misma clave?

Los códigos hash acotan la búsqueda; la igualdad la confirma

Un HashMap utiliza hashCode() para ayudar a localizar una clave y equals() para comprobar una coincidencia. Las claves iguales deben tener códigos hash iguales. Las claves distintas pueden compartir un código hash; la igualdad sigue permitiendo distinguirlas. Las clases estándar de valores como String e Integer ya cumplen este contrato.

Sin sobrescrituras, una clase hereda de Object una igualdad basada en la identidad. Dos puntos creados por separado con coordenadas 2 y 3 son claves distintas aunque sus campos coincidan:

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

Con igualdad por identidad, label es null. La búsqueda creó un segundo objeto, distinto del utilizado para la inserción.

Sobrescribe el par conjuntamente

Aquí las coordenadas de un punto definen su contenido:

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);
    }
}

La comprobación de identidad gestiona rápidamente el caso del mismo objeto. La comprobación de tipo rechaza null y los objetos de otros tipos. La comparación final comprueba ambas coordenadas. Objects.hash(x, y) construye el código hash a partir de esos mismos campos. Con esta clase, la búsqueda anterior devuelve "door".

Sobrescribir solo equals deja el cálculo del código hash heredado, que no garantiza códigos iguales para objetos separados con campos iguales. Un mapa puede entonces no encontrar una clave igual. Un código hash constante conservaría la corrección, pero haría lenta la búsqueda. Generar ambas sobrescrituras en un editor ayuda a evitar que se utilicen campos distintos.

Utiliza la firma exacta del método

public boolean equals(Point other) sobrecarga el método; no reemplaza equals(Object). La búsqueda en un mapa utiliza equals(Object), por lo que la nueva sobrecarga no proporciona al mapa igualdad por contenido. La anotación @Override convierte una firma incorrecta en un error del compilador en lugar de un error oculto de búsqueda.

Mantén estable la identidad de la clave

No cambies los campos que determinan la igualdad o el código hash de una clave mientras esté almacenada. Si un punto almacenado cambia de (2, 3) a (5, 3), puede que el mapa ya no lo encuentre con ninguno de los dos valores aunque size() no haya cambiado. Elimínalo antes de cambiarlo y luego vuelve a insertarlo. Declarar los campos de la clave como final, como arriba, evita este error.

Estas reglas también determinan la pertenencia a un HashSet. Un ArrayList utiliza equals para búsquedas por contenido como contains; no necesita códigos hash para esa búsqueda.

Puntos clave

  • Los objetos iguales deben tener códigos hash iguales; los objetos distintos pueden compartir uno.
  • Sobrescribe equals(Object) y hashCode() utilizando los mismos campos.
  • @Override detecta una sobrecarga de equals creada por error.
  • Mantén sin cambios los campos de igualdad y código hash mientras una clave esté almacenada.
2

Cuenta, agrupa e indexa datos con mapas

Un mapa puede construir información útil mientras un programa lee datos: un recuento por palabra, una lista por curso o un objeto por identificador. La elección importante es qué representa cada valor. Un número acumula un resultado; una lista o un conjunto reúne un grupo; una referencia a un objeto proporciona un índice. Sigue cada actualización desde un mapa vacío para que el comportamiento de las primeras apariciones, las claves repetidas y los objetos compartidos quede claro.

2.1 Cuenta apariciones y acumula totales por clave

Una tabla de frecuencias tiene una clave por cada elemento distinto y un número que indica cuántas veces aparece. La primera aparición inicia un recuento; cada aparición posterior actualiza esa misma entrada.

Construye un recuento elemento por elemento
HashMap<String, Integer> counts = new HashMap<>();
for (String word : text.split(" ")) {
    int oldCount = counts.getOrDefault(word, 0);
    counts.put(word, oldCount + 1);
}

Para el texto «el gato vio el perro y el gato corrió», la primera «el» no está en el mapa, por lo que su recuento anterior es 0 y el nuevo es 1. Sus dos apariciones siguientes cambian esa entrada a 2 y luego a 3. «gato» termina en 2; «vio», «perro», «y» y «corrió» terminan en 1 cada una. En el texto original, las claves correspondientes son "the", "cat", "saw", "dog", "and" y "ran".

Hay 6 palabras distintas, por lo que counts.size() es 6. Los valores suman 9, el número de apariciones de palabras. Estas medidas son diferentes: el tamaño del mapa no es la longitud de la secuencia original.

La actualización puede escribirse en una línea:

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

Una forma equivalente más larga comprueba containsKey, incrementa un recuento existente y almacena 1 para una clave nueva. Todos los recuentos almacenados en este patrón son distintos de null.

Conserva el resultado anterior

Llamar a counts.put(word, 1) para cada palabra sobrescribe repetidamente cada recuento con 1. Registra que una palabra existe, pero pierde su frecuencia. Llamar a counts.get(word) + 1 sin gestionar la primera aparición intenta desempaquetar null y falla. El valor predeterminado pertenece al paso de lectura; después hay que volver a almacenar el recuento incrementado.

Decide qué se considera el mismo elemento

La igualdad de cadenas es exacta. "The" y "the" son claves distintas, al igual que "cat" y "cat,". Si la tarea las trata como la misma palabra, limpia cada unidad de entrada antes de contarla. Convierte el texto a minúsculas y elimina la puntuación que el programa trate como separadores. Utiliza una regla consistente para que los resultados no dependan de qué forma escrita apareció primero.

La clave también puede ser un carácter. Con HashMap<Character, Integer>, un bucle sobre "banana".toCharArray() produce a=3, n=2 y b=1 mediante el mismo patrón de leer, incrementar y almacenar.

Acumula cantidades en lugar de apariciones

Para obtener totales por categoría, suma la cantidad actual en lugar de 1:

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

Comida 12,50, transporte 3,20 y comida 7,25 dan comida 19,75 y transporte 3,20. El valor predeterminado es 0.0, que coincide con el tipo de valor Double. El mapa sigue teniendo una entrada por categoría, independientemente de cuántas cantidades contribuyan a ella.

Interpreta la tabla completa

Recorre las entradas para encontrar el mayor recuento o total, recordando la mejor clave y su valor. Especifica una regla de desempate si es necesario. Para un informe alfabético, new TreeMap<>(counts) copia las asociaciones en orden de clave. Los valores de los recuentos permanecen sin cambios; ordenar las claves no ordena las categorías por sus totales.

Puntos clave

  • Un mapa de frecuencias almacena un recuento por cada clave distinta.
  • Lee el recuento anterior con cero como valor predeterminado, suma uno y almacena el resultado.
  • El tamaño del mapa cuenta elementos distintos; la suma de los recuentos mide las apariciones.
  • Normaliza el texto de forma consistente antes de contar.
  • Utiliza el mismo patrón de actualización para sumar cantidades por clave.
  • Elige el orden del informe de forma independiente de los valores acumulados.

2.2 Agrupa valores bajo una misma clave utilizando listas y conjuntos como valores

El valor de un mapa puede ser una colección. Cuando varios estudiantes pertenecen a un curso, el curso es una clave y la lista asociada contiene a todos sus estudiantes. La regla de claves únicas del mapa sigue vigente: la lista es el único valor de ese curso.

Crea un grupo antes de añadir elementos
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» y «blueberry», la primera fruta crea la lista de a y añade «apple». «Banana» crea la lista de b. «Avocado» encuentra la lista existente de a y se añade al final. El resultado es a → [apple, avocado], b → [banana, blueberry] y c → [cherry]. Cada lista conserva su propio orden de inserción aunque el HashMap no ordene sus claves.

La comprobación puede abreviarse:

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

putIfAbsent conserva una lista existente distinta de null. El get siguiente devuelve esa lista, lista para la adición.

Conserva la lista que ya has construido

Un groups.put(letter, new ArrayList<>()) incondicional dentro del bucle reemplaza la lista anterior en cada aparición. Solo queda la última fruta de cada letra después del siguiente add. El error contrario es omitir la creación por completo: groups.get(letter).add(fruit) lanza una NullPointerException para una clave nueva porque aún no existe ninguna lista.

Comprende la referencia

get devuelve la referencia a la lista almacenada. Añadir elementos a ella modifica esa misma lista, por lo que no hay que volver a insertarla. Esto también explica un error al compartir:

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

Ambas claves conducen ahora a [Jin]. Dos claves no crearon dos listas. Crea una lista nueva para cada grupo nuevo cuando los grupos deban ser independientes.

Elige listas o conjuntos dentro de los grupos

Una lista conserva las adiciones repetidas. Un conjunto evita duplicados dentro de ese grupo. Por tanto, un HashMap<String, HashSet<String>> puede recopilar las inscripciones en cursos de cada estudiante sin contar dos veces al mismo estudiante en un curso. La regla del conjunto se aplica dentro de cada valor; el mapa externo sigue teniendo una entrada por curso.

Para leer un grupo que podría faltar, comprueba containsKey o utiliza groups.getOrDefault(letter, new ArrayList<>()). Una clave ausente produce entonces una lista vacía para esa llamada. La lista predeterminada no se inserta automáticamente; añadir elementos a ella no crea un grupo almacenado.

Eliminar el último elemento de un grupo deja la clave asociada a una colección vacía. Si el programa debe dejar de listar grupos vacíos, comprueba isEmpty() y elimina también esa clave. Cuenta los grupos con el tamaño del mapa externo y los elementos con los tamaños de las colecciones internas.

Puntos clave

  • Asegúrate de que exista un grupo y después añade a su lista o conjunto almacenado.
  • Crea una colección nueva para cada grupo independiente.
  • get devuelve la referencia almacenada, por lo que los cambios internos no necesitan otro put.
  • Los valores de tipo lista conservan repeticiones; los de tipo conjunto conservan miembros distintos del grupo.
  • Un grupo vacío almacenado sigue teniendo una entrada en el mapa.

2.3 Busca objetos y precios rápidamente con un índice basado en un mapa

Un índice asocia una clave identificadora con un objeto. Una biblioteca puede encontrar un libro por ISBN sin recorrer todos los libros de una lista. Una tabla de consulta utiliza la misma estructura para relacionar un código con un valor sencillo, como el precio de un producto.

Elige una clave identificadora

Un HashMap<String, Book> puede asociar un ISBN con su libro. Cada búsqueda solo necesita la clave. El nombre de una persona suele ser una mala clave única: almacenar a otra persona llamada «Sam Lee» bajo esa misma cadena reemplaza a la persona anterior. Utiliza un identificador único o un mapa de agrupación si un nombre debe conducir a varias personas.

Mantén un índice dentro de la clase responsable de los datos:

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);
    }
}

Aquí Book proporciona un método getIsbn(). Quienes llaman utilizan addBook y findByIsbn; no necesitan saber qué implementación de mapa se almacena. El campo privado también proporciona a la clase un único lugar donde mantener sus reglas para añadir y reemplazar libros.

Comprueba si falta un resultado

Si findByIsbn devuelve null, no se encontró ningún libro. Comprueba el resultado antes de llamar a un método sobre él:

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

Llamar a setOnLoan directamente sobre un resultado ausente lanzaría una NullPointerException. Un método como hasBook(isbn) es otra forma de permitir que quienes llaman comprueben si existe una clave.

Sigue los objetos compartidos entre índices

Un mapa almacena una referencia a un objeto, no una copia nueva de ese objeto. Si el mismo libro está en una lista de todos los libros, un mapa por ISBN y una agrupación por autor, setOnLoan(true) cambia el único libro al que hacen referencia los tres. Esto evita que tres objetos de libro separados dejen de coincidir.

Las propias estructuras de las colecciones siguen necesitando mantenimiento. Eliminar un libro del mapa por ISBN no elimina su referencia de la lista de un autor. Si una biblioteca mantiene ambos índices, sus métodos de adición y eliminación deben actualizar los dos. Centralizar esos cambios en métodos como addBook y removeBook ayuda a mantener la coherencia de las búsquedas.

Utiliza una tabla en un cálculo

Supón que una tabla de precios contiene café 2,50, té 2,00 y magdalena 3,25 u.m. Para dos cafés y una magdalena:

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

El subtotal del café es 5,00; sumar 3,25 da 8,25 u.m. Las claves identifican productos y los valores proporcionan los importes. Un producto ausente requiere una decisión explícita antes del cálculo: un valor predeterminado de cero lo trataría como gratuito sin avisar. Por tanto, la misma técnica de búsqueda puede necesitar una regla para claves ausentes diferente de la de una tabla de frecuencias.

Puntos clave

  • Un índice encuentra objetos mediante una clave identificadora.
  • Utiliza una clave única o agrupa explícitamente varios objetos coincidentes.
  • Los índices comparten referencias a objetos, pero las adiciones y eliminaciones deben actualizar cada índice.
  • Mantén privados los mapas de datos y ofrece métodos que mantengan sus reglas.
3

Conserva valores únicos con conjuntos

A veces la pregunta es simplemente si un valor ha aparecido antes. Los conjuntos responden directamente a esa pregunta y también pueden comparar grupos de valores, como las personas que asisten a dos eventos. La ausencia de elementos duplicados cambia tanto el código que escribes como el significado del tamaño final. Trabaja primero con la pertenencia y después combina conjuntos y elige si sus valores deben aparecer en orden de inserción o en orden.

3.1 Almacena valores únicos y comprueba la pertenencia con HashSet

Un conjunto contiene cada valor como máximo una vez. Es adecuado para preguntas como «¿ha aparecido antes este valor?» o «¿cuántos valores diferentes aparecen?». Un HashSet permite comprobaciones de pertenencia rápidas en promedio sin garantizar un orden de presentación.

Añade y comprueba 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");

Los tres booleanos almacenados son true, true y false. El segundo «Oslo» coincide con un elemento existente, por lo que no se añade. El tamaño del conjunto es 3. Una adición duplicada no reemplaza una posición numerada porque un conjunto no tiene índices.

visited.contains("Lima") devuelve true. visited.remove("Lima") lo elimina y devuelve true; repetir esa eliminación devuelve false. Utiliza un bucle for-each para visitar los valores. No existe get(0) para obtener el primer valor de un HashSet.

Elimina duplicados de una 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);

El conjunto tiene tres valores: {1, 2, 3}. Su orden de iteración real no está especificado. La lista original sigue teniendo cinco elementos porque el constructor crea una colección independiente.

Utiliza new LinkedHashSet<>(values) para conservar el orden de la primera aparición, lo que da 3, 1, 2. Utiliza new TreeSet<>(values) para obtener los valores ordenados, 1, 2, 3. Aquí los conjuntos se escriben entre llaves para destacar la pertenencia; el toString() estándar de los conjuntos de Java utiliza corchetes.

Detecta la primera repetición

El resultado de add puede realizar conjuntamente la comprobación de pertenencia y la inserción:

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

Para [4, 7, 2, 7, 4], el bucle imprime 7. Es el primer valor encontrado por segunda vez, aunque 4 apareció antes en la secuencia. Antes de que se repita 7, el conjunto contiene 4, 7 y 2. La inserción fallida provoca la detención.

Identifica lo que un conjunto no puede decirte

Comprobar contains antes de cada add es innecesario porque add ya gestiona los duplicados. Una lista con una comprobación de contains también puede mantener valores únicos, pero cada búsqueda en la lista puede recorrer todos los elementos almacenados. Un HashSet expresa la regla directamente.

La igualdad importa para tus propios objetos. Un HashSet<Point> necesita un equals basado en el contenido y un hashCode coherente para reunir puntos creados por separado con coordenadas iguales. Sin esas sobrescrituras, las instancias separadas permanecen como elementos distintos.

Por último, size() mide valores distintos, no apariciones. Las nueve palabras de «el gato vio el perro y el gato corrió» producen seis palabras distintas. Un conjunto ya no te indica que «el» apareció tres veces; utiliza un mapa de frecuencias cuando esos recuentos importen.

Puntos clave

  • HashSet almacena valores únicos sin índices ni orden garantizado.
  • add devuelve false cuando ya hay un valor igual.
  • Un conjunto copiado elimina duplicados sin modificar la lista original.
  • Utiliza el resultado de add para detectar un valor repetido.
  • El tamaño de un conjunto cuenta valores distintos; las frecuencias necesitan un mapa.

3.2 Combina conjuntos y mantén su orden

Los conjuntos pueden describir grupos y comparar su pertenencia. Si dos listas de eventos contienen varias veces a la misma persona, un conjunto reduce primero cada lista a las personas que asistieron. Las operaciones de conjuntos responden después a preguntas sobre cualquiera de los dos eventos, ambos o solo uno.

Combina dos grupos

Sean los asistentes del lunes {Ana, Ben, Cai, Dee} y los del martes {Ben, Dee, Eva}.

PreguntaMétodo sobre una copia del lunesResultado
¿Quién asistió cualquiera de los dos días?addAll(tuesday){Ana, Ben, Cai, Dee, Eva}
¿Quién asistió ambos días?retainAll(tuesday){Ben, Dee}
¿Quién asistió solo el lunes?removeAll(tuesday){Ana, Cai}

Estas operaciones son la unión, la intersección y la diferencia. Modifican el conjunto receptor y devuelven un booleano que indica si cambió. No devuelven un conjunto nuevo con el resultado.

Conserva el original

Haz una copia antes de cambiar la pertenencia si aún necesitas el conjunto del lunes:

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

both empieza con los cuatro nombres del lunes. retainAll elimina a Ana y Cai porque no están el martes. El conjunto del lunes permanece sin cambios. Para encontrar a quienes asistieron solo el martes, empieza con una copia del martes y elimina los nombres del lunes; el resultado es {Eva}. La diferencia tiene un sentido; invertirlo cambia la pregunta.

Comprueba subconjuntos e igualdad

monday.containsAll(group) pregunta si todos los valores de group están presentes el lunes. Para {Ben, Dee}, devuelve true: ese grupo es un subconjunto del lunes. No exige que el conjunto del lunes contenga solo a esas dos personas.

Dos conjuntos son iguales cuando sus elementos coinciden, independientemente del orden de inserción o de la implementación. Un HashSet que contiene «x» e «y» es igual a un TreeSet que contiene «y» y «x». La pertenencia determina la igualdad de conjuntos, por lo que el orden por sí solo no puede hacerlos distintos.

Elige un orden para el recorrido
ImplementaciónOrden al visitar los elementos
HashSetSin garantía
LinkedHashSetOrden de inserción
TreeSetOrden según los valores

Los tres evitan duplicados. Utiliza LinkedHashSet cuando importe la primera vez que apareció cada nombre. Utiliza TreeSet cuando cada recorrido deba estar ya ordenado. Para las cadenas, la ordenación natural sigue los códigos de carácter: las formas en minúsculas y mayúsculas no se comportan como un único alfabeto que no distingue entre ellas.

Un TreeSet con su constructor predeterminado necesita elementos que tengan una comparación natural, como cadenas, números u objetos que implementen Comparable. En ese conjunto, un resultado de comparación igual a cero indica un duplicado. Una clase que no proporciona una comparación natural provoca una ClassCastException al insertarse. Proporcionar un comparador explícito es otra forma de definir el orden de una colección basada en árboles; los ejemplos predeterminados utilizan el orden natural.

Puntos clave

  • addAll, retainAll y removeAll modifican el conjunto receptor.
  • Copia primero un conjunto cuando aún necesites su pertenencia original.
  • containsAll comprueba un subconjunto; la igualdad de conjuntos ignora el orden.
  • Elige implementaciones basadas en hash, enlazadas o en árbol para obtener un orden no especificado, de inserción u ordenado.
4

Programa con las interfaces List, Set y Map

El tipo a la izquierda de una declaración de colección indica al resto del programa qué operaciones puede utilizar. La clase de la derecha proporciona esas operaciones y puede garantizar un orden concreto. Aprender a interpretar ambos lados facilita cambiar el código que utiliza colecciones y reutilizar métodos. También ayuda a explicar por qué una lista, un conjunto y un mapa se comportan de forma distinta incluso cuando contienen datos de aspecto similar.

4.1 Declara variables y parámetros con tipos de interfaz

Una interfaz describe las operaciones que proporciona una clase que la implementa. Permite que una variable describa lo que necesita el código y deja la elección del almacenamiento a una clase concreta. List, Set y Map son interfaces relacionadas con colecciones en java.util.

Interpreta los dos lados de una declaración
List<String> names = new ArrayList<>();
Set<String> tags = new HashSet<>();
Map<String, Integer> counts = new HashMap<>();

El lado izquierdo declara el tipo de la variable. El derecho crea un objeto de una clase que lo implementa. Importa ambos tipos, como java.util.List y java.util.ArrayList. No puedes escribir new List<>() ni new Map<>(): una interfaz no es un objeto concreto que se pueda construir.

El código que utiliza counts puede llamar a put, get y entrySet porque Map los declara. Si resulta útil tener las claves en orden alfabético, cambia la construcción a new TreeMap<>(). Las llamadas existentes siguen compilándose. Su orden puede cambiar porque las implementaciones pueden ofrecer distintas garantías de orden; la interfaz no hace que su comportamiento sea idéntico en todo.

Acepta la capacidad que necesita un método

Un método que solo cuenta palabras largas puede aceptar una 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»] y un mínimo de 4, devuelve 2. El mismo método puede recibir un ArrayList, un LinkedList, un HashSet o List.of(...) porque solo lee los elementos. Un conjunto puede haber eliminado ya los duplicados, por lo que puede proporcionar datos de entrada distintos de los de una lista.

Utilizar un parámetro de tipo interfaz evita exigir una clase de almacenamiento concreta cuando el método no la necesita. Si se necesitan posiciones, acepta List. Si se necesita buscar por clave, acepta Map.

Conoce los límites del tipo declarado
List<String> names = new ArrayList<>();
names.ensureCapacity(100);  // does not compile

El objeto es un ArrayList, pero List no declara ensureCapacity. El compilador comprueba el tipo declarado de la variable. Utiliza un tipo de clase concreta cuando realmente necesites su operación especial; no cambies los parámetros de lista habituales solo para que coincidan con la clase de quien los llama.

Sitúa Map junto a Collection

List y Set extienden Collection, que describe un grupo de elementos. Declara métodos como add, remove, contains, size, isEmpty, addAll y clear. Que se admita una modificación depende de la colección real.

Map no extiende Collection. Almacena asociaciones y proporciona vistas que son colecciones: keySet() es un Set, values() es una Collection y entrySet() es un Set de entradas. Pasa counts.values() a un método que necesite una colección de valores, no counts directamente.

Una clase puede implementar varias interfaces. LinkedList implementa tanto List como Deque, una interfaz de cola de doble extremo. Tu propia clase indica las interfaces que se compromete a implementar después de implements, como en class Member implements Comparable<Member>.

Puntos clave

  • Declara la interfaz necesaria a la izquierda y construye una clase que la implemente a la derecha.
  • Los parámetros de tipo interfaz aceptan distintas implementaciones que proporcionan las operaciones necesarias.
  • Una variable solo permite acceder a los métodos declarados por su tipo.
  • List y Set extienden Collection; Map proporciona vistas de colección.

4.2 Identifica qué garantizan List, Set y Map

Elige una interfaz según las reglas que necesiten tus datos. Que su contenido parezca similar no hace intercambiables una lista, un conjunto y un mapa: cada uno da un significado diferente a las posiciones, las repeticiones y la igualdad.

Compara las garantías
InterfazQué almacenaRegla importante
ListElementos en posiciones que empiezan en 0Se permiten elementos repetidos
SetElementos distintosNo tiene una operación get por índice
MapPares clave-valorLas claves son únicas; los valores pueden repetirse

ArrayList y LinkedList implementan List. HashSet, LinkedHashSet y TreeSet implementan Set. HashMap, LinkedHashMap y TreeMap implementan Map. Las versiones basadas en hash no garantizan ningún orden de recorrido; las versiones enlazadas conservan el orden de inserción; las versiones basadas en árboles mantienen ordenados los elementos o las claves. Volver a insertar una clave existente en un LinkedHashMap normal con orden de inserción conserva la posición de esa clave.

Examina con cuidado la eliminación en listas de enteros

Una List<Integer> tiene dos métodos sobrecargados relevantes:

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

El argumento 1 es un int, por lo que Java elimina el elemento del índice 1: el valor 5. El resultado es [1, 7]. Si vuelves a empezar con [1, 5, 7], numbers.remove(Integer.valueOf(1)) selecciona la eliminación por valor y deja [5, 7]. El objeto envoltorio deja claro qué método sobrecargado se pretende utilizar.

Compara el contenido con la regla adecuada

Dos listas son iguales cuando los mismos elementos aparecen en el mismo orden. Un ArrayList [1, 2] es igual a un LinkedList [1, 2], pero no a una lista [2, 1]. Dos conjuntos comparan la pertenencia e ignoran el orden. Dos mapas comparan las asociaciones, por lo que el orden de inserción no afecta a la igualdad de mapas. Sus clases concretas pueden ser distintas aunque sus contenidos sean iguales según la regla de la interfaz.

Reconoce las colecciones no modificables
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);

Estas fábricas devuelven colecciones no modificables. Los intentos de añadir, eliminar, reemplazar u ordenar su contenido lanzan UnsupportedOperationException. Map.of acepta hasta diez pares clave-valor.

Las tres rechazan elementos, claves o valores null con NullPointerException. Set.of rechaza elementos duplicados y Map.of rechaza claves duplicadas con IllegalArgumentException. List.of permite duplicados porque una lista puede repetir un elemento. El orden de iteración de los conjuntos y mapas creados por estas fábricas no está especificado.

Haz una copia cuando necesites modificar

new ArrayList<>(labels) crea una lista modificable con los mismos elementos. new HashSet<>(someList) y new HashMap<>(someMap) también crean estructuras de colección independientes.

Estas copias son superficiales: contienen las mismas referencias a elementos. Eliminar un elemento de una copia deja intacta la estructura original, pero modificar un objeto mutable a través de cualquiera de las dos colecciones cambia el objeto compartido. Una colección no modificable impide editar su estructura; no congela todos los objetos almacenados en ella.

Puntos clave

  • Las listas tienen posiciones y duplicados; los conjuntos tienen elementos distintos; los mapas tienen claves únicas.
  • remove(1) en una lista de enteros elimina por índice; remove(Integer.valueOf(1)) elimina por valor.
  • La igualdad de listas comprueba el orden; la de conjuntos y mapas comprueba el contenido sin tener en cuenta el orden de inserción.
  • Las fábricas of crean colecciones no modificables y rechazan valores null.
  • Set.of rechaza elementos duplicados; Map.of rechaza claves duplicadas.
  • Una copia modificable separa la estructura de la colección, pero comparte las referencias a elementos.
5

Ordena colecciones con Comparable

La ordenación coloca los valores en un orden que otro código puede utilizar. Los números y las cadenas ya tienen un orden natural; los objetos de tus propias clases necesitan una regla explícita. Sigue una lista durante una ordenación y después escribe una comparación que gestione de forma segura números, texto y empates. La regla importa más allá de las listas: un conjunto o mapa ordenado también la utiliza para decidir cuándo dos elementos o claves ocupan la misma posición.

5.1 Ordena listas de números y cadenas

Una lista conserva un orden, pero ese orden puede simplemente reflejar cómo llegaron los valores. La ordenación reorganiza la lista mediante una regla de comparación. Java ya proporciona un orden natural para números y cadenas.

Ordena una lista modificable in situ
List<Double> values = new ArrayList<>(List.of(3.5, -1.0, 2.25));
Collections.sort(values);

Importa java.util.Collections. La misma lista contiene ahora [-1,0; 2,25; 3,5]. La ordenación devuelve void, por lo que values = Collections.sort(values) no se compila. values.sort(null) también ordena en orden natural. Para un arreglo, utiliza Arrays.sort(array); un arreglo que contiene 5, 2 y 8 pasa a contener 2, 5 y 8.

Predice el orden de las cadenas carácter por carácter

La comparación de cadenas examina el primer carácter diferente. Si una cadena es prefijo de otra, la más corta va primero. Así, «apple» precede a «apples».

La lista [«pear», «Banana», «apple», «10», «9»] se ordena como [«10», «9», «Banana», «apple», «pear»]. Para estos caracteres, los dígitos preceden a las letras mayúsculas y las mayúsculas preceden a las minúsculas. «10» precede a «9» porque «1» va antes que «9»; el orden de cadenas no interpreta las cadenas de dígitos como números enteros. Almacena los datos numéricos como números cuando necesites un orden numérico.

Utiliza órdenes alternativos ya disponibles
names.sort(String.CASE_INSENSITIVE_ORDER);
values.sort(Collections.reverseOrder());

La primera llamada ordena [«pear», «Banana», «apple»] como [«apple», «Banana», «pear»] sin cambiar las mayúsculas y minúsculas almacenadas. La segunda utiliza el orden natural descendente. Los números 4, 9 y 1 pasan a ser 9, 4 y 1. Estos argumentos son comparadores, objetos que proporcionan un orden alternativo.

Collections.reverse(list) solo invierte la secuencia actual. Produce un orden descendente si esa secuencia ya estaba ordenada de forma ascendente; por sí solo no ordena una lista cualquiera.

Conserva la estabilidad de los empates

La ordenación de listas es estable: los elementos que se comparan como iguales conservan su orden relativo anterior. Si una comparación basada solo en la puntuación empata a dos personas, se mantiene el orden que tenían en la lista. La estabilidad conserva ese orden de entrada; no inventa un criterio de desempate alfabético.

Reconoce fallos y métodos útiles

Una lista creada con List.of(...) no se puede ordenar in situ. Cópiala primero a un ArrayList. Para una clase que no implementa Comparable, Collections.sort(list) no supera la comprobación de tipos durante la compilación. Llamar a list.sort(null) sobre esos objetos falla en tiempo de ejecución con ClassCastException cuando se necesita comparar.

Collections.max(collection) y Collections.min(collection) encuentran los elementos mayor y menor en orden natural sin reorganizar la colección. Lanzan NoSuchElementException para una colección vacía.

Para obtener las claves de un mapa ordenadas, copia map.keySet() a un ArrayList y ordena la copia, o utiliza un TreeMap. Ordenar una lista de claves copiada deja sin cambios el orden de iteración del propio mapa.

Puntos clave

  • Collections.sort modifica una lista modificable in situ y devuelve void.
  • El orden natural de las cadenas compara caracteres, no valores numéricos escritos como texto.
  • Utiliza comparadores ya disponibles para el orden inverso o sin distinguir mayúsculas y minúsculas.
  • La ordenación estable conserva el orden relativo anterior de los elementos empatados.
  • Copia una lista no modificable antes de ordenarla.
  • min y max encuentran valores extremos sin ordenar.

5.2 Implementa Comparable en tu propia clase

Java no puede adivinar si un miembro debe ir primero por nombre, altura u otro campo. Implementa Comparable para dotar a la clase de un orden natural. El código de ordenación puede entonces pedir a cada objeto que se compare con otro objeto de esa clase.

Escribe el método de comparación
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);
    }
}

La altura se mide en centímetros. Comparable<Member> especifica que el otro objeto es un Member; no se necesita una conversión explícita. public int compareTo(Member other) es el método requerido. La interfaz estándar Comparable está en java.lang, por lo que no necesita importación.

Para a.compareTo(b), un resultado negativo coloca a antes que b, cero los sitúa en la misma posición de comparación y un resultado positivo coloca a después de b. Solo importa el signo: -35 es un resultado negativo tan válido como -1.

Sigue el orden

Con la comparación por altura, Ana 172, Ben 165 y Cai 180 se ordenan como Ben 165, Ana 172 y Cai 180. Para colocar primero a los miembros más altos, intercambia los argumentos:

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

Cambia la regla de forma deliberada. Invertir los argumentos invierte el sentido de ese campo; no cambia lo que significa la altura ni modifica los datos de ningún miembro.

Compara valores numéricos completos de forma segura

La resta parece cómoda, pero puede devolver el signo incorrecto cuando un int se desborda. Para -2 000 000 000 y 2 000 000 000, restar el segundo del primero produce por desbordamiento 294 967 296, un resultado positivo. Integer.compare devuelve correctamente un resultado negativo.

Para campos decimales, utiliza Double.compare(this.price, other.price). Convertir explícitamente una diferencia a int pierde información: (int) (1.8 - 1.5) es 0, por lo que precios distintos se convierten en un empate de comparación. Un método de comparación conserva el orden sin truncar la diferencia.

Compara texto y reutiliza la regla

Para ordenar por nombre, devuelve this.name.compareTo(other.name). Sigue el orden por unidades de código de la cadena. compareToIgnoreCase proporciona una comparación de texto que no distingue mayúsculas y minúsculas cuando esa es la regla prevista para el campo.

Una vez que una clase define su orden natural, operaciones como Collections.sort, Collections.max y las comparaciones predeterminadas de TreeSet o TreeMap pueden utilizarlo. Una clase también puede implementar otras interfaces, separadas por comas después de implements.

La clase tiene un único orden natural; no se selecciona un compareTo diferente para cada lista. Utiliza objetos comparadores separados cuando un contexto necesite ordenar por nombre y otro por altura. Una comparación solo por altura también empata todas las alturas iguales; decidir si ese empate es aceptable es especialmente importante en los conjuntos ordenados.

Puntos clave

  • Implementa Comparable<YourClass> con un método público compareTo.
  • Los resultados negativo, cero y positivo significan antes, empate y después.
  • Utiliza Integer.compare y Double.compare para ordenar números de forma segura.
  • Intercambia los argumentos de comparación para invertir el sentido de un campo.
  • Una clase tiene un orden natural; los comparadores proporcionan otros órdenes.

5.3 Resuelve empates y utiliza conjuntos y mapas ordenados

Una comparación principal a menudo deja empates. Dos películas pueden compartir año o dos jugadores pueden compartir puntuación. Un criterio de desempate da paso al siguiente campo solo cuando los campos anteriores se comparan como iguales.

Compara los campos por orden de prioridad
@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);
}

El año es el criterio principal. El título solo importa cuando los años empatan. Up (2009), Avatar (2009) y Alien (1979) se ordenan como Alien (1979), Avatar (2009), Up (2009). Comparar primero los títulos les daría prioridad sobre el año y resolvería una tarea de ordenación diferente.

Los sentidos pueden ser distintos según el campo. Para poner primero los puntos más altos y ordenar los nombres de la A a la Z, empieza con Integer.compare(other.points, this.points). Si el resultado es cero, devuelve this.name.compareTo(other.name). Invertir toda la lista final también invertiría los nombres dentro de las puntuaciones empatadas.

Comprende la regla de duplicados de un conjunto ordenado

Un TreeSet<Member> predeterminado utiliza la comparación natural tanto para ordenar elementos como para decidir cuándo un elemento ya está presente. Si Member.compareTo utiliza solo la altura, Ana 172 y Dee 172 se comparan como cero. Añadir a Ana devuelve true; añadir a Dee devuelve false. Ana permanece como elemento almacenado aunque equals considere diferentes a las dos personas.

Una lista puede conservar ambos objetos empatados; un conjunto basado en árbol les asigna una sola posición de comparación. Añade el criterio de desempate necesario si deben ser distintos en el conjunto.

Alinea la comparación con la igualdad

Un orden es consistente con equals cuando la comparación devuelve cero si y solo si equals devuelve verdadero. Para una clase cuya igualdad utiliza altura y nombre, comparar la altura y luego el nombre puede cumplir esta regla. Si la igualdad utiliza una identidad diferente, como un identificador de miembro, añadir solo el nombre como criterio de desempate no establece la consistencia.

La comparación también debe comportarse como un orden correcto. Si a va antes que b, la comparación inversa debe colocar b después de a. Si a va antes que b y b antes que c, a debe ir antes que c. Utilizar métodos que comparan campos completos en un orden fijo de prioridad ayuda a cumplir estas reglas. Un método inconsistente puede ordenar mal los resultados o hacer que una ordenación lance IllegalArgumentException.

Mantén también ordenadas las claves de los mapas

Un TreeMap ordena las claves, no los valores. Para los recuentos de palabras de «el gato vio el perro y el gato corrió», la primera clave es «corrió» y la última es «y». firstKey() y lastKey() proporcionan esos extremos. Declara un TreeMap o una interfaz de mapa ordenado adecuada cuando llames a métodos que Map no declara.

La comparación de claves también define qué claves coinciden. Una segunda clave que se compare como cero actualiza la asociación existente, aunque equals distinga los objetos. Las colecciones basadas en árboles predeterminadas requieren elementos o claves comparables naturalmente; insertar un objeto sin una comparación adecuada lanza ClassCastException. Un comparador proporcionado explícitamente puede definir otro orden.

Puntos clave

  • Compara primero el campo principal y consulta los siguientes solo si hay empate.
  • Invierte solo los campos que necesiten orden descendente.
  • Las colecciones basadas en árboles tratan una comparación igual a cero como el mismo elemento o clave.
  • La consistencia con equals requiere que la comparación dé cero exactamente cuando la igualdad sea verdadera.
  • TreeMap ordena las claves; sus métodos de extremos devuelven las claves extremas.
  • Una comparación debe invertir los signos de forma consistente y conservar el orden entre ternas.
6

Elige la colección adecuada para una tarea

La elección de una colección comienza con las preguntas a las que debe responder el programa: por posición, por pertenencia o por una clave independiente. El orden y los duplicados acotan aún más la elección. Una vez que los datos se ajustan a la tarea, compara cómo crece el coste de las operaciones frecuentes a medida que llegan más valores. Un pequeño cambio, como crear un conjunto antes de un bucle, puede eliminar búsquedas repetidas sin dificultar la lectura del programa.

6.1 Compara el coste de las operaciones habituales con colecciones

El coste de una operación describe cómo crece su trabajo con el número de elementos almacenados. Ayuda a identificar código que es rápido para un ejemplo pequeño, pero lento cuando la colección crece.

Compara el crecimiento, no los segundos

El tiempo constante, O(1), se mantiene aproximadamente independiente del tamaño de la colección. El tiempo lineal, O(n), puede crecer en proporción al número de elementos. El tiempo logarítmico, O(log n), crece lentamente al aumentar el tamaño. Estas etiquetas describen el crecimiento, no tiempos de ejecución exactos en un equipo concreto.

ColecciónOperaciónCoste
ArrayListget(i), set(i, x)Constante
ArrayListAñadir al finalConstante en promedio
ArrayListcontains, indexOf, eliminación por valorLineal
ArrayListInsertar o eliminar cerca del principioLineal
HashMap / HashSetBúsqueda básica por clave o pertenencia, inserción, eliminaciónConstante en promedio con códigos hash bien distribuidos
TreeMap / TreeSetBúsqueda básica, inserción, eliminaciónLogarítmico
LinkedListAñadir o eliminar en cualquiera de los extremosConstante
LinkedListget(i) en generalLineal

Una búsqueda en un ArrayList puede comprobar todos los elementos; las modificaciones al principio desplazan los elementos posteriores. Un LinkedList debe recorrer la lista hasta llegar a una posición, por lo que acceder repetidamente por índice puede ser costoso. ArrayList es una opción predeterminada útil para el trabajo habitual con listas.

Detecta el recorrido repetido

Supón que un programa comprueba 10 000 nombres frente a una lista que contiene 100 000 nombres. Llamar a list.contains(name) para cada nombre puede requerir hasta 1 000 000 000 de comprobaciones de igualdad. Una llamada a un método que parece rápida sigue siendo una búsqueda completa cuando se utiliza de esta forma.

Construye una vez un conjunto para comprobar la pertenencia:

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

Hay trabajo para construir el conjunto de 100 000 elementos, seguido de 10 000 comprobaciones de pertenencia de tiempo constante en promedio. Contando ambas etapas, el total crece aproximadamente con la suma de los tamaños de las dos entradas, en lugar de con su producto. Volver a construir el conjunto dentro del bucle repetiría el trabajo de preparación y perdería esa ventaja.

Interpreta correctamente las garantías promedio

Las operaciones basadas en hash dependen de claves cuyos códigos hash distribuyan bien los valores. Devolver un código hash constante para todos los objetos puede seguir cumpliendo los requisitos de igualdad, pero hace lenta la búsqueda. No es una forma gratuita de evitar escribir un método hash útil.

Las colecciones basadas en árboles mantienen el orden con operaciones básicas de tiempo logarítmico. Duplicar el número de elementos añade solo una pequeña cantidad de trabajo de búsqueda. Para 100 000 elementos, un logaritmo en base dos es aproximadamente 16,6; esto sugiere la escala de la búsqueda, no una garantía exacta de 17 comparaciones en cada búsqueda en un árbol de Java.

Ten en cuenta toda la tarea

Construir un conjunto adicional cuesta tiempo y memoria. Para unos pocos elementos o una sola búsqueda, la lista original puede ser suficiente. Para comprobaciones de pertenencia repetidas, un conjunto reutilizable suele eliminar el coste principal. Empieza por el comportamiento requerido y después examina las operaciones que se repiten con más frecuencia.

Puntos clave

  • Las etiquetas de crecimiento describen cómo escala el trabajo, no un número medido de segundos.
  • ArrayList ofrece acceso rápido por índice, pero las búsquedas y las modificaciones al principio son lineales.
  • Las búsquedas basadas en hash son constantes en promedio con códigos hash adecuados; las búsquedas en árboles son logarítmicas.
  • Construye una vez un conjunto para comprobar la pertenencia y sustituir recorridos repetidos de listas.
  • Incluye el tiempo de preparación y la memoria al comparar soluciones completas.

6.2 Selecciona una colección que se ajuste a la tarea

La colección adecuada conserva la información que necesita el programa y facilita expresar sus preguntas principales. Decide las reglas de los datos antes de elegir el nombre de una clase conocida.

Pregunta qué identifica un elemento
Necesidad principalElección inicialEjemplo
Encontrar un valor mediante una clave independienteMapCódigo de producto asociado a precio
Comprobar pertenencia sin duplicadosSetNombres de usuario ocupados
Conservar posiciones, orden o elementos repetidosListUna lista de reproducción que repite canciones
Conservar un número fijo de posicionesArregloDoce mediciones mensuales de precipitación

Un double[12] puede contener la precipitación en milímetros cuando cada posición corresponde a un mes conocido. Un mapa cuyas claves son solo las posiciones 0, 1, 2 y así sucesivamente añade una capa que una lista o un arreglo ya proporciona.

Elige el orden que necesitas

Para mapas y conjuntos, utiliza HashMap o HashSet cuando no se requiera un orden, LinkedHashMap o LinkedHashSet para el orden de inserción y TreeMap o TreeSet para claves o elementos ordenados. Para una lista de uso general, empieza con ArrayList.

Los recuentos de palabras impresos en orden alfabético se ajustan a un TreeMap<String, Integer>. Una lista de etiquetas distintas en el orden en que aparecieron por primera vez se ajusta a un LinkedHashSet<String>. Las canciones repetidas necesitan una lista aunque también estén almacenadas en otro lugar en un conjunto: descartar las repeticiones cambiaría la lista de reproducción.

Combina colecciones cuando los datos tienen capas

Los estudiantes por curso pueden representarse con Map<String, List<String>>; cada valor es una lista ordenada de inscripciones. Las etiquetas por artículo pueden representarse con Map<String, Set<String>>; cada artículo obtiene etiquetas distintas. Una clasificación puede ser una List<Player> ordenada según la comparación natural del jugador.

Las elecciones externas e internas responden a preguntas diferentes. Si los cursos deben listarse en orden alfabético y los estudiantes deben conservarse en orden de inscripción, utiliza un TreeMap por fuera y una lista por dentro. Ordenar las claves no ordena las listas. Si deben ignorarse los registros de inscripción duplicados, utiliza un conjunto para los grupos internos.

Mantén juntos los datos relacionados

Dos listas paralelas, una para nombres y otra para números de teléfono, dependen de que las posiciones coincidan. Eliminar un nombre sin su número desajusta todos los pares posteriores. Si los nombres identifican de forma única a las personas, un mapa puede contener la asociación. Si los nombres se repiten o varios campos pertenecen a una persona, conserva objetos de persona en una lista o indéxalos mediante un identificador único.

Buscar una y otra vez en una lista por un campo es otra señal para considerar un índice basado en un mapa. Conserva también la lista si importan el orden de presentación y las entradas repetidas, pero mantén ambas estructuras coordinadas cuando se añadan o eliminen datos.

Comprueba las reglas de los elementos y el tipo declarado

Utiliza una declaración de interfaz como Map<String, Double> prices = new HashMap<>(); para que quienes llaman dependan de las operaciones de mapa que necesitan. Las colecciones basadas en hash necesitan una igualdad significativa y códigos hash coherentes para claves o elementos propios. Las colecciones basadas en árboles predeterminadas necesitan una comparación natural que distinga exactamente los valores que la colección debe conservar. Estas reglas forman parte de conseguir que la colección elegida represente los datos previstos.

Puntos clave

  • Elige mapas para búsquedas por clave, conjuntos para pertenencia y listas para posiciones o repeticiones.
  • Los arreglos pueden contener un número fijo de posiciones, incluidos valores primitivos.
  • Elige de forma deliberada el orden de inserción o el orden según los valores.
  • Las colecciones anidadas permiten que las claves externas y los grupos internos sigan reglas diferentes.
  • Mantén juntos los campos relacionados y actualiza varios índices mediante métodos compartidos.
  • Ajusta las reglas de igualdad y comparación a los valores que la colección debe conservar.

Ejemplos de HashMap y colecciones en Java

6 Lecciones Interactivas

1

Sigue un mapa de existencias desde el almacenamiento hasta la búsqueda

13 pasos
Sigue los cambios, examina las entradas de forma segura y haz que se puedan encontrar claves propias.
  1. 1
    IntroducciónEmpieza con una pregunta sobre un producto

    Un programa de existencias necesita responder «¿cuántas carpetas hay disponibles?». Un mapa convierte el nombre del producto en la clave y su cantidad en el valor. Sigue un mapa durante un reemplazo, una búsqueda sin resultado y una limpieza. Después examina por qué una clave propia puede fallar aunque sus campos parezcan correctos. Cada búsqueda depende de lo que Java considera la misma clave.

  2. 2
    ExplicaciónCrea una asociación por clave

    Crea HashMap<String, Integer> stock = new HashMap<>();. String describe las claves; Integer describe los valores. El mapa utiliza tipos de referencia, por lo que int no puede ser el argumento de tipo del valor. Java empaqueta un literal como 6 cuando stock.put("folder", 6) lo almacena. El diamante de la derecha permite que Java infiera los dos tipos.

  3. 3
    EjemploReemplaza una cantidad

    Ejecuta estas actualizaciones en orden:

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

    La última llamada encuentra la clave folder existente, almacena 8 y devuelve 6 en old. Sigue habiendo dos claves. Un mapa registra el valor más reciente de una clave; no suma automáticamente las cantidades ni conserva un historial de ellas.

  4. 4
    DesafíoLee sin insertar

    ¿Cuáles son los valores de n y stock.size() después de esta lectura? El mapa sigue teniendo folder 8 y clip 11.

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

    ---reveal---

    n es 0 y el tamaño sigue siendo 2. El valor predeterminado es un resultado para una clave ausente, no una entrada insertada. Leer con get("tape") devuelve null, que no se puede desempaquetar como un int.

  5. 5
    ExplicaciónLee los pares juntos

    Un bucle sobre entradas proporciona cada clave y su valor juntos:

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

    Importa java.util.Map. El bucle puede mostrar ambas asociaciones sin un get adicional. Si solo se necesita un total, recorre stock.values() y suma las cantidades; las cantidades repetidas siguen contribuyendo por separado.

  6. 6
    Idea claveNo des por supuesta la primera entrada

    La salida podría mostrar folder antes que clip o clip antes que folder. HashMap no garantiza ninguno de los dos órdenes. Un resultado como una suma no se ve afectado, pero una regla que conserva la primera puntuación empatada puede depender del recorrido. Elige LinkedHashMap para el orden de inserción o TreeMap para ordenar las claves, y establece una regla de desempate explícita para los máximos empatados cuando el ganador deba ser predecible.

  7. 7
    EjemploElimina durante el recorrido

    Supón que folder es ahora 0 y clip es 11. Elimina las cantidades cero con un iterador:

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

    El iterador elimina su entrada actual y continúa de forma segura. Llamar a stock.remove desde un recorrido for-each puede, en cambio, provocar ConcurrentModificationException.

  8. 8
    DesafíoDistingue una copia de claves

    Antes de la limpieza, keys se crea con new ArrayList<>(stock.keySet()). Si se llama a keys.remove("folder"), ¿qué ocurre con el mapa de existencias?

    ---reveal---

    El mapa conserva su asociación para folder. keys es una lista independiente de las claves que existían cuando se hizo la copia. Eliminar de stock.keySet() directamente eliminaría la entrada del mapa, porque ese objeto es una vista vinculada.

  9. 9
    EjemploPrueba una clave propia

    Imagina que Bin tiene los campos row y column y no sobrescribe los métodos de igualdad. Almacena una etiqueta utilizando new Bin(3, 4) y después búscala utilizando otro new Bin(3, 4). La búsqueda devuelve null. Son dos objetos distintos y Object.equals heredado utiliza la identidad. Los valores coincidentes de los campos todavía no se han convertido en una regla de coincidencia de claves.

  10. 10
    ExplicaciónHaz coherentes la igualdad y el código hash

    Para definir la identidad de un contenedor según sus coordenadas, sobrescribe equals(Object other) para comparar la fila y la columna, y sobrescribe hashCode() utilizando los mismos campos, por ejemplo, Objects.hash(row, column). Las coordenadas iguales deben producir códigos hash iguales. Un código hash coincidente por sí solo no establece la igualdad; la comprobación de igualdad sigue distinguiendo las claves con coordenadas diferentes.

  11. 11
    DesafíoDetecta una sobrecarga

    Una clase define public boolean equals(Bin other) y hashCode() a partir de sus coordenadas. ¿Por qué puede seguir fallando una búsqueda con otro contenedor que parece igual?

    ---reveal---

    El parámetro debe ser Object para sobrescribir el método de igualdad de Java. El método con parámetro Bin es una sobrecarga y deja vigente la igualdad por identidad heredada. Añadir @Override a esa firma incorrecta hace que el compilador muestre el error.

  12. 12
    DesafíoCorrige un diseño con claves que cambian

    Una clave de contenedor utiliza la fila y la columna en ambos métodos de igualdad. El programa cambia su fila mientras está almacenada y después no puede encontrar su etiqueta. ¿Cómo debe actualizar la ubicación y luego eliminar de forma segura las etiquetas vacías durante el recorrido?

    ---reveal---

    Elimina la asociación antes de cambiar la clave y después vuelve a insertarla. Para la limpieza durante el recorrido, utiliza el método de eliminación del propio iterador de entradas. La identidad estable de la clave y el recorrido seguro resuelven partes distintas de esta actualización.

  13. 13
    RepasoMantén una lista de comprobación para actualizar mapas

    Para una búsqueda sin resultado, decide si un valor predeterminado o una comprobación explícita de ausencia se ajusta a la tarea. Para un bucle, decide si el orden importa y si se eliminarán claves. Para una clave propia, comprueba la firma exacta de equals(Object), que se utilicen los mismos campos para el código hash y que la identidad sea estable. Estas comprobaciones localizan distintas causas de un mismo síntoma: una asociación que el programa no puede utilizar como se esperaba.

2

Construye información de asistencia a medida que llegan registros

12 pasos
Cuenta registros, agrupa miembros distintos y mantén coherentes los índices de búsqueda.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónConvierte las llegadas en respuestas útiles
  2. 2
    EjemploInicia un recuento de sesiones
  3. 3
    EjemploDistingue las sesiones distintas de los registros
  4. 4
    DesafíoCorrige un recuento que se reinicia
  5. 5
    ExplicaciónCrea un grupo una sola vez
  6. 6
    EjemploSigue la referencia interna
  7. 7
    DesafíoEncuentra el error de grupo compartido
  8. 8
    ExplicaciónIndexa mediante una clave identificadora
  9. 9
    Idea claveModifica un objeto en varios lugares
  10. 10
    DesafíoMantén la coherencia al eliminar
  11. 11
    DesafíoCombina recuentos con pertenencia sin duplicados
  12. 12
    RepasoComprueba una primera llegada y una repetición
3

Compara dos grupos de asistencia

9 pasos
Utiliza la pertenencia a conjuntos, conserva los originales y presenta la diferencia correcta.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónPregunta quién asistió, no cuántas visitas hubo
  2. 2
    EjemploElimina los escaneos repetidos
  3. 3
    DesafíoDetente en la primera llegada repetida
  4. 4
    EjemploConserva solo los miembros compartidos
  5. 5
    ExplicaciónElige el sentido de la diferencia
  6. 6
    DesafíoComprueba un grupo seleccionado
  7. 7
    ConsejoElige un orden útil para el informe
  8. 8
    DesafíoCrea un informe ordenado de ausencias
  9. 9
    RepasoInterpreta el receptor como grupo inicial
4

Interpreta declaraciones y copias de colecciones

10 pasos
Utiliza interfaces, identifica sobrecargas y distingue la estructura de los objetos compartidos.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónInterpreta ambos lados de la declaración
  2. 2
    ExplicaciónDeclara lo que necesita quien llama
  3. 3
    EjemploUtiliza un parámetro más general para leer
  4. 4
    DesafíoIdentifica el problema del método ausente
  5. 5
    ConexiónElige el significado del contenido
  6. 6
    EjemploSigue la eliminación de enteros
  7. 7
    DesafíoCopia antes de ordenar
  8. 8
    Idea claveDistingue las modificaciones de objetos de las de listas
  9. 9
    DesafíoPasa la vista de mapa adecuada
  10. 10
    RepasoComprueba el tipo, la operación y el objeto
5

Construye una clasificación que conserve los empates correctos

15 pasos
Ordena cadenas y objetos, escribe comparaciones seguras y comprueba la pertenencia a conjuntos ordenados.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónElige qué va primero
  2. 2
    EjemploOrdena la misma lista
  3. 3
    ExplicaciónExamina el primer carácter diferente
  4. 4
    DesafíoUtiliza un orden disponible
  5. 5
    ExplicaciónDota a una clase de un orden natural
  6. 6
    EjemploEvita un falso empate numérico
  7. 7
    DesafíoInvierte el campo numérico
  8. 8
    EjemploResuelve solo los empates reales
  9. 9
    EjemploSigue la clasificación paso a paso
  10. 10
    DesafíoObserva qué conserva un conjunto basado en árbol
  11. 11
    Idea claveAjusta la ordenación a la identidad
  12. 12
    ConexiónComprueba la clave de un mapa ordenado
  13. 13
    DesafíoConserva todos los resultados en una lista ordenada
  14. 14
    ConsejoHaz que la regla funcione con ternas
  15. 15
    RepasoComprueba una comparación en dos contextos
6

Elige estructuras para una lista de participantes de cursos

10 pasos
Ajusta la búsqueda, la pertenencia, el orden y el coste sin recorridos repetidos.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónEnumera las preguntas que hace el programa
  2. 2
    EjemploDetecta el recorrido dentro del bucle
  3. 3
    ExplicaciónPrepara una sola vez la comprobación de pertenencia
  4. 4
    DesafíoCompara entradas que crecen
  5. 5
    EjemploConserva los registros de inscripción repetidos
  6. 6
    ExplicaciónElige el orden externo e interno
  7. 7
    DesafíoCorrige la regla incorrecta para duplicados
  8. 8
    ConsejoAsume el coste del orden que necesitas
  9. 9
    DesafíoCombina el diseño final
  10. 10
    RepasoElige el comportamiento antes de medir la velocidad

Ejercicios de HashMap y colecciones en Java

50 Preguntas de Práctica en 5 sets

Set 1: Construye recuentos y compara grupos10 Preguntas de Práctica

Pregunta 1 de 10

La secuencia es [12, 7, 4, 12, 7]. Un bucle se detiene en el primer !seen.add(n). ¿Qué número se muestra?
  1. 7
  2. 4
  3. 12
  4. Ningún número.
Mostrar respuestaOcultar respuesta
Respuesta: C
Los primeros 12, 7 y 4 entran correctamente en el conjunto vacío. El siguiente 12 es la primera adición fallida, por lo que detiene el bucle. Aunque 7 también aparece dos veces, su segunda aparición llega después; la pregunta se refiere a la primera llegada repetida, no al menor valor repetido.

Pregunta 2 de 10

El mismo objeto Device está almacenado en una lista y en un mapa por identificador. Se recupera del mapa y después cambia su campo de estado. ¿Qué estado muestra la referencia almacenada en la lista?
  1. El estado cambiado del mismo objeto.
  2. El estado original de un objeto copiado aparte.
  3. Null hasta que se reemplace la entrada de la lista.
  4. El estado cambiado solo después de otro put en el mapa.
Mostrar respuestaOcultar respuesta
Respuesta: A
Ambas estructuras contienen referencias a un único objeto Device, por lo que cambiar su campo es visible inmediatamente a través de cualquiera de las dos referencias. El mapa no creó una copia independiente de Device al insertarlo. No se necesita un nuevo put para cambiar un campo, aunque los cambios de pertenencia requieren mantenimiento por separado.

Pregunta 3 de 10

Un mapa de frecuencias registra "north" → 4, "south" → 2 y "west" → 3. ¿Cuántas claves distintas contiene?
  1. 9
  2. 4
  3. 3
  4. 2
Mostrar respuestaOcultar respuesta
Respuesta: C
Hay una clave para cada uno de north, south y west, por lo que el mapa tiene tres claves distintas. Sumar 4, 2 y 3 da nueve apariciones, una cantidad diferente. El tamaño de un mapa de frecuencias cuenta categorías, no cuántos registros de entrada contribuyeron a ellas.

Pregunta 4 de 10

Un HashSet ya contiene "cedar". ¿Qué devuelve otra llamada a add("cedar")?
  1. false
  2. true
  3. null
  4. La cadena almacenada.
Mostrar respuestaOcultar respuesta
Respuesta: A
El valor ya pertenece al conjunto, por lo que la pertenencia no cambia y add devuelve false. Una primera adición que tiene éxito devuelve true. El valor de retorno indica si hubo un cambio, no es el propio elemento ni un recuento de las veces que el programa intentó añadirlo.

Pregunta 5 de 10

Un curso debe listar a cada participante una sola vez aunque lleguen registros de inscripción duplicados. ¿Qué regla de colección interna se ajusta a cada grupo de curso?
  1. Una lista de identificadores de participantes.
  2. Un recuento entero de registros.
  3. Un identificador de participante como cadena.
  4. Un conjunto de identificadores de participantes.
Mostrar respuestaOcultar respuesta
Respuesta: D
Un conjunto conserva identificadores distintos dentro del curso, por lo que un registro repetido no añade un segundo miembro. Una lista conservaría ambas apariciones salvo que código adicional de comprobación de duplicados las eliminara. Un recuento puede medir las llegadas, pero no puede proporcionar la lista de miembros solicitada.

Pregunta 6 de 10

El bucle procesa "red", "gold", "red", "blue", "gold", "red" utilizando counts.put(word, counts.getOrDefault(word, 0) + 1). ¿Cuáles son el recuento de red y el tamaño del mapa?
  1. Recuento de red 1; tamaño 3.
  2. Recuento de red 3; tamaño 3.
  3. Recuento de red 3; tamaño 6.
  4. Recuento de red 6; tamaño 3.
Mostrar respuestaOcultar respuesta
Respuesta: B
Red aparece tres veces, por lo que su único recuento almacenado aumenta de 1 a 2 y luego a 3. Gold y blue crean las otras dos claves, así que el tamaño es 3. Un tamaño de 6 cuenta apariciones en lugar de claves distintas; el reemplazo actualiza una asociación existente sin aumentar el número de claves.

Pregunta 7 de 10

Dentro de un bucle de agrupación, cada llegada ejecuta groups.put(team, new ArrayList<>()); seguido de groups.get(team).add(name);. Un equipo recibe a Omar, Pia y después Ren. ¿Qué queda bajo ese equipo?
  1. [Omar, Pia, Ren]
  2. [Ren]
  3. [Omar]
  4. Una lista vacía.
Mostrar respuestaOcultar respuesta
Respuesta: B
Cada put reemplaza el grupo por una lista vacía nueva antes de añadir el nombre. Por tanto, la última llegada deja solo a Ren. Para conservar todos los nombres, crea la lista solo en la primera llegada y añade los nombres posteriores al mismo grupo almacenado en lugar de reiniciarlo.

Pregunta 8 de 10

A = {2, 5, 8, 11} y B = {5, 11, 14}. Un conjunto copiado C comienza con A y después ejecuta C.removeAll(B). ¿Qué contiene C?
  1. {5, 11}
  2. {14}
  3. {2, 5, 8, 11, 14}
  4. {2, 8}
Mostrar respuestaOcultar respuesta
Respuesta: D
La diferencia comienza con A y elimina los valores que también están en B, por lo que desaparecen 5 y 11 y quedan 2 y 8. {14} es la diferencia opuesta, B menos A. El conjunto receptor determina el sentido y la copia mantiene disponible el A original sin cambios.

Pregunta 9 de 10

Un mismo ArrayList está almacenado tanto bajo "Morning" como bajo "Evening". El programa añade "Lee" mediante Morning, después reemplaza la asociación de Evening por una lista nueva y añade "Jo" mediante Evening. ¿Cuáles son los grupos finales?
  1. Morning [Lee]; Evening [Jo].
  2. Morning [Lee, Jo]; Evening [Lee, Jo].
  3. Morning []; Evening [Lee, Jo].
  4. Morning [Jo]; Evening [Jo].
Mostrar respuestaOcultar respuesta
Respuesta: A
La primera adición modifica la lista que inicialmente comparten ambas claves. Reemplazar después el valor de Evening hace que Evening haga referencia a una lista vacía distinta; añadir Jo modifica solo esa lista nueva. Morning sigue haciendo referencia a la lista original [Lee], por lo que se deja de compartir después del reemplazo.

Pregunta 10 de 10

A = {1, 3, 6} y B = {3, 6, 9}. C se copia de A y ejecuta retainAll(B). D se copia de B y ejecuta removeAll(C). ¿Cuáles son D y el resultado de A.containsAll(C)?
  1. D = {1}; el resultado es true.
  2. D = {9}; el resultado es false.
  3. D = {3, 6, 9}; el resultado es false.
  4. D = {9}; el resultado es true.
Mostrar respuestaOcultar respuesta
Respuesta: D
C se convierte en la intersección {3, 6}. Eliminar C de una copia de B deja solo 9, mientras que A sigue conteniendo todos los elementos de C. La copia conservó A y containsAll permite el elemento adicional 1 de A. Sería incorrecto exigir tamaños iguales para esa comprobación de subconjunto.
Set 2: Lee y actualiza mapas de forma fiable10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Un HashMap<String, Integer> vacío recibe put("brush", 5) y después put("brush", 14). ¿Cuáles son su tamaño y el valor de "brush"?
  1. Tamaño 2; valor 14.
  2. Tamaño 1; valor 14.
  3. Tamaño 1; valor 19.
  4. Tamaño 2; valor 5.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Un mapa de cantidades no nulas no tiene la clave "tray". ¿Qué ocurre al ejecutar int n = map.get("tray");?
  1. Almacena 0 en n y continúa.
  2. Lanza ClassCastException.
  3. Inserta "tray" con valor 0.
  4. Lanza NullPointerException.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

Un bucle debe leer de un mapa cada identificador de dispositivo junto con su estado. ¿Qué vista proporciona ambos en un solo elemento del bucle?
  1. entrySet()
  2. keySet()
  3. values()
  4. map.keySet().toArray()
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Dos objetos separados son iguales según un método equals correcto. ¿Cómo deben ser sus códigos hash?
  1. Valores enteros diferentes.
  2. Sus números de campos.
  3. El mismo valor entero.
  4. Sus direcciones de memoria.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un mapa contiene "beam" → 9. El programa ejecuta Integer old = map.put("beam", 13); y después Integer removed = map.remove("beam");. ¿Cuáles son old, removed y el tamaño final?
  1. 13, 13 y 0.
  2. 9, 9 y 0.
  3. 9, 13 y 1.
  4. 9, 13 y 0.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un bucle de limpieza de existencias recorre entrySet() y debe eliminar cada entrada cuyo valor sea cero. ¿Cómo debe eliminar la entrada durante el recorrido?
  1. Utilizar el iterador de ese recorrido y llamar a su remove() después de next().
  2. Utilizar un bucle for-each y llamar a remove() del mapa con cada clave de valor cero.
  3. Utilizar un bucle sobre entradas y reemplazar cada valor cero por null.
  4. Utilizar un bucle sobre valores y eliminar directamente cada clave de valor cero de keySet().
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Una clase Cell define equals(Cell other) y un hashCode basado en campos. Las celdas separadas con campos iguales no coinciden como claves de HashMap. ¿Qué cambio de método corrige el error de igualdad?
  1. Conservar equals(Cell other) y devolver un código hash constante.
  2. Sobrescribir equals(Object other) con las mismas comparaciones de campos.
  3. Reemplazar el método de igualdad por un toString() basado en campos.
  4. Añadir compareTo(Cell other) sin cambiar ninguno de los métodos de igualdad.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Una búsqueda en un HashMap registra una clave solo cuando su puntuación es estrictamente mayor que la mejor puntuación encontrada hasta el momento. Dos claves empatan con la puntuación más alta. ¿Qué resultado puede garantizar el programa?
  1. Una de las claves empatadas, sin un orden de desempate garantizado.
  2. La clave empatada insertada primero en el mapa.
  3. La clave empatada cuyo nombre va primero alfabéticamente.
  4. La clave empatada insertada más recientemente en el mapa.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Un mapa comienza con "ink" → 4 y "paper" → 0. keys es un ArrayList nuevo copiado de su conjunto de claves. El programa elimina "ink" de keys, elimina "paper" mediante la vista de conjunto de claves del mapa y después duplica todos los valores que quedan en el mapa. ¿Qué queda en el mapa?
  1. Solo "paper" → 0.
  2. No queda ninguna asociación.
  3. Solo "ink" → 8.
  4. Tanto "ink" → 8 como "paper" → 0.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

La igualdad y el cálculo del código hash de Location utilizan una coordenada mutable. Se almacena una clave y después se cambia su coordenada mientras está almacenada; ahora la búsqueda no encuentra su asociación. ¿Qué secuencia de actualización debe utilizar el diseño para evitar este fallo?
  1. Cambiar la coordenada; obtener por la coordenada nueva; volver a insertar.
  2. Eliminar antes de la mutación; cambiar la coordenada; volver a insertar.
  3. Cambiar la coordenada; reemplazar equals; obtener por la coordenada anterior.
  4. Conservar una segunda referencia; cambiar la coordenada; buscar con ella.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 3: Utiliza interfaces y ordena datos10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

En Set<String> codes = new HashSet<>();, ¿cuál es el tipo declarado de codes?
  1. HashSet<String>
  2. String
  3. Collection<HashSet>
  4. Set<String>
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Qué significa un valor positivo devuelto por a.compareTo(b)?
  1. a va antes que b en ese orden.
  2. a y b empatan en ese orden.
  3. a va después de b en ese orden.
  4. a tiene un campo numérico mayor.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

Una List<Integer> mutable comienza como [4, 8, 12]. Ejecuta remove(1). ¿Qué queda?
  1. [4, 12]
  2. [8, 12]
  3. [4, 8]
  4. [4, 8, 12]
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Cuál es el orden natural de las cadenas "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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un método de solo lectura acepta Collection<String>. Quien llama tiene Map<String, String> labels y quiere que el método procese cada valor de etiqueta. ¿Qué debe pasarse?
  1. labels.values()
  2. labels
  3. labels.entrySet()
  4. labels.keySet().iterator()
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Una comparación de precios devuelve (int) (this.price - other.price). ¿Qué falla para los precios 6,8 y 6,3?
  1. Siempre coloca 6,8 antes que 6,3.
  2. Desborda el rango de int.
  3. Devuelve cero para precios distintos.
  4. Cambia ambos precios almacenados a enteros.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Los resultados deben ordenarse por puntos, de mayor a menor, y después por nombre de la A a la Z. La comparación principal es distinta de cero. ¿Qué debe hacer compareTo a continuación?
  1. Comparar los nombres y devolverlo.
  2. Devolver cero para mantener el orden de entrada.
  3. Devolver una comparación de nombres negada.
  4. Devolver esa comparación principal.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Una lista modificable contiene un objeto Ticket mutable. Se copia de ella un segundo ArrayList. El programa cambia la etiqueta del ticket mediante la copia y después vacía la copia. ¿Qué contiene la lista original?
  1. Una lista vacía en la que no queda ningún ticket.
  2. El mismo ticket con su etiqueta modificada.
  3. Un ticket independiente con su etiqueta original.
  4. El mismo ticket con su etiqueta original.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Una clase compara por nivel descendente y después por código ascendente. Los registros son Delta 2, Beta 4, Alpha 2 y Echo 4. ¿Qué orden resulta?
  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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Reading.equals utiliza el identificador de estación y la temperatura, pero su comparación natural utiliza solo la temperatura. Un TreeSet predeterminado recibe A con 16, B con 16 y después C con 12. ¿Cuáles son su tamaño y los identificadores conservados?
  1. Tamaño 2; identificadores C y A.
  2. Tamaño 3; identificadores C, A y B.
  3. Tamaño 2; identificadores C y B.
  4. Tamaño 1; solo el identificador C.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 4: Identifica problemas en el comportamiento de las colecciones10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Un programa almacena la precipitación en milímetros en una posición para cada uno de los doce meses. Necesita un número fijo de posiciones numéricas primitivas. ¿Qué estructura se ajusta directamente?
  1. Un Set<Double> de mediciones.
  2. Un arreglo double[12].
  3. Un Map<Double, String> de meses.
  4. Un HashSet<Integer> de números de mes.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Un HashMap contiene la clave "pending" asociada explícitamente a null. ¿Qué devuelve getOrDefault("pending", 20)?
  1. 20
  2. 0
  3. null
  4. Una excepción de la propia búsqueda.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Qué ocurre al evaluar Set.of("draft", "final", "draft")?
  1. Lanza IllegalArgumentException.
  2. Devuelve un conjunto con dos elementos.
  3. Devuelve una lista con tres elementos.
  4. Lanza UnsupportedOperationException.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Un índice de miembros utiliza los nombres mostrados como claves. Se insertan dos miembros distintos llamados "Ari Chen" y ya no se puede recuperar al primero por ese nombre. ¿Qué diseño conserva directamente a ambos para búsquedas individuales?
  1. Mantener el nombre como clave, pero usar TreeMap.
  2. Mantener el nombre como clave en un LinkedHashMap.
  3. Volver a llamar a put con el mismo nombre.
  4. Indexar por el identificador único de cada miembro.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Una lista mutable contiene actualmente [10, 2, 7]. ¿Cuál es su contenido después de Collections.reverse(list)?
  1. [10, 7, 2]
  2. [2, 7, 10]
  3. [7, 10, 2]
  4. [7, 2, 10]
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un programa comprueba repetidamente si hay identificadores en un ArrayList grande y no necesita posiciones para esas comprobaciones. ¿Qué cambio evita repetir todo el trabajo de búsqueda?
  1. Construir un HashSet nuevo dentro del bucle de consultas.
  2. Copiar el ArrayList una vez a un LinkedList.
  3. Construir un HashSet antes del bucle de consultas.
  4. Ordenar un ArrayList nuevo para cada consulta.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Un mapa de agrupación no tiene la clave "Support". El programa evalúa List<String> result = groups.getOrDefault("Support", new ArrayList<>()); y después añade "Nia" a result. ¿Qué devuelve una llamada posterior a groups.get("Support")?
  1. null, porque nunca se insertó el valor predeterminado.
  2. Una lista con Nia, porque el valor predeterminado se convirtió en el grupo.
  3. Una lista vacía, porque el valor predeterminado se almacenó antes de la adición.
  4. Una excepción, porque una lista predeterminada no almacenada no se puede modificar.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

La igualdad de ScoreKey utiliza equipo y puntos; su comparación natural utiliza solo puntos. Un TreeMap predeterminado recibe la clave East-30 con valor "old", West-30 con valor "new" y después North-18 con valor "low". ¿Cuáles son su tamaño y el valor encontrado mediante East-30?
  1. Tamaño 3; el valor es "old".
  2. Tamaño 2; el valor es "new".
  3. Tamaño 2; el valor es "old".
  4. Tamaño 1; el valor es "low".
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

A = {4, 7, 10} y B = {7, 10, 13}. Una copia U ejecuta primero addAll(B) y después removeAll(A). ¿Qué es U y cambió alguno de los originales?
  1. U = {4}; ambos originales siguen sin cambios.
  2. U = {4, 13}; solo cambia A.
  3. U = {7, 10}; solo cambia B.
  4. U = {13}; ambos originales siguen sin cambios.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Un informe necesita los cursos en orden alfabético y los identificadores distintos de los miembros de cada curso en orden de primera inscripción. ¿Qué implementaciones externa e interna se ajustan juntas?
  1. TreeMap por fuera; LinkedHashSet por dentro.
  2. LinkedHashMap por fuera; TreeSet por dentro.
  3. TreeMap por fuera; ArrayList por dentro.
  4. HashMap por fuera; LinkedHashSet por dentro.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 5: Combina búsqueda, agrupación y orden10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Un mapa contiene dos claves diferentes asociadas cada una a 6. ¿Qué total produce sumar map.values()?
  1. 12
  2. 6
  3. 2
  4. 1
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Una clase de temperatura debe comparar dos campos double en orden ascendente sin falsos empates causados por una conversión explícita. ¿Qué expresión de retorno se ajusta?
  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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Qué determina la igualdad entre un ArrayList y un LinkedList que contienen los mismos valores de elementos?
  1. Los valores deben aparecer en el mismo orden.
  2. Las listas deben tener la misma clase concreta.
  3. Solo debe coincidir el número de valores distintos.
  4. Las referencias a los elementos deben ser todas idénticas.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Un mapa de totales inicialmente vacío procesa reparaciones 4,25, entrega 2,50 y reparaciones 3,75 mediante una suma con cero como valor predeterminado. ¿Cuáles son su tamaño y el total de reparaciones?
  1. Tamaño 3; total de reparaciones 8,00.
  2. Tamaño 2; total de reparaciones 3,75.
  3. Tamaño 2; total de reparaciones 10,50.
  4. Tamaño 2; total de reparaciones 8,00.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Una clase propia con igualdad correcta devuelve el mismo código hash para cada instancia. ¿Qué ocurre con la corrección y el rendimiento de búsqueda de HashSet?
  1. Todos los valores se reúnen en un elemento y la búsqueda se acelera.
  2. Los valores distintos siguen siendo válidos, pero las búsquedas pueden ralentizarse.
  3. Los valores distintos siguen siendo válidos, con búsqueda en tiempo constante garantizada.
  4. Todas las inserciones fallan al compilarse porque los códigos hash se repiten.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un catálogo conserva los mismos objetos Item en un índice por identificador y en un índice que asocia cada categoría con una lista. La categoría de un artículo cambia de Cables a Adapters. Cambiar solo su campo de categoría lo deja en la lista Cables. ¿Qué actualización mantiene coherentes los índices?
  1. Reemplazarlo en el mapa por identificador; dejar ambas listas de categorías como están.
  2. Cambiar el mapa por identificador a TreeMap; dejar ambas listas de categorías como están.
  3. Mover su referencia entre las listas de categorías; conservar su asociación por identificador.
  4. Copiar el artículo bajo la categoría anterior; eliminar su asociación por identificador.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Una clase de jugador define la igualdad por nombre y puntuación y compara por puntuación descendente y después por nombre ascendente. Un TreeSet predeterminado recibe Mira 9, Axel 12, Mira 9 y Bo 9 como objetos separados. ¿Qué miembros quedan y en qué orden?
  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 respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Un programa tiene una lista de valores admitidos y una lista de consultas. Ambos tamaños se duplican. Compara las búsquedas completas repetidas en la lista con construir un HashSet de valores admitidos y después consultarlo, suponiendo un cálculo del código hash adecuado. ¿Cómo crece el trabajo total?
  1. Ambos totales pueden cuadruplicarse porque ambas entradas contienen el doble de valores.
  2. El trabajo de búsqueda en la lista puede cuadruplicarse; construir y consultar el conjunto se duplica aproximadamente.
  3. El trabajo de búsqueda en la lista se duplica aproximadamente; construir y consultar el conjunto permanece constante.
  4. Ambos totales permanecen constantes porque cada uno utiliza una llamada a método por consulta.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Un mapa agrupa notas por proyecto. Dos proyectos deben mantener listas independientes, notas repetidas y orden de llegada. El código existente crea un ArrayList compartido, lo coloca bajo cada clave nueva y añade notas mediante get. ¿Qué corrección completa conserva los requisitos?
  1. Conservar el ArrayList compartido, pero reemplazar cada get por getOrDefault usando esa misma lista.
  2. Crear un ArrayList nuevo para cada clave nueva y después añadir mediante su referencia almacenada.
  3. Crear un HashSet nuevo para cada clave nueva y después añadir notas mediante su referencia almacenada.
  4. Crear un ArrayList vacío nuevo para el proyecto en cada llegada y después añadir la nota actual.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Un sistema de documentos necesita etiquetas únicas en orden de primera aparición, búsqueda directa de objetos por identificador único de documento y un historial ordenado independiente que conserve las visitas repetidas. ¿Qué estructuras se ajustan a las tres necesidades?
  1. TreeSet para etiquetas; List para búsqueda por identificador; HashSet para el historial.
  2. HashSet para etiquetas; Map para búsqueda por identificador; TreeSet para el historial.
  3. LinkedHashSet para etiquetas; Set para búsqueda por identificador; Map por identificador de documento para el historial.
  4. LinkedHashSet para etiquetas; Map para búsqueda por identificador; List para el historial.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

¿Te atascas con una pregunta tuya? Ayuda con Tareas

Términos Clave

70 Términos Clave, cada uno con su definición

A

Agrupación
La agrupación reúne elementos con una propiedad compartida bajo una clave de mapa y utiliza una lista o un conjunto como valor para almacenar cada grupo.
Una clave de curso puede conducir a una lista de estudiantes, mientras que una clave de primera letra puede conducir a palabras que coinciden con ella.
Arreglo
Un arreglo almacena un número fijo de elementos indexados de un mismo tipo y puede contener valores primitivos directamente sin argumentos de tipo envoltorio.
Un double[12] puede dar a cada mes una posición para su medición de precipitación en milímetros.

B

Búsqueda por clave
Una búsqueda por clave encuentra un valor mediante un identificador independiente, lo que hace útil un mapa cuando las búsquedas repetidas tendrían que examinar campos de objetos.
Un mapa por código de producto responde directamente a consultas de precios, mientras que una lista necesitaría buscar el código correspondiente.

C

Clase envoltorio
Una clase envoltorio proporciona un tipo de objeto para un valor primitivo, lo que permite utilizar números y otros datos primitivos como argumentos de tipo de colecciones.
Un mapa de cantidades utiliza Integer como tipo de valor porque int no puede aparecer como argumento de tipo genérico.
Clase HashMap
Un HashMap es un mapa modificable de Java que almacena claves únicas con valores asociados y no garantiza ningún orden de iteración concreto.
Un HashMap<String, Integer> puede buscar el recuento actual de un producto sin utilizar una posición de lista.
Clase HashSet
Un HashSet es un conjunto modificable de Java con operaciones básicas de tiempo constante en promedio si el cálculo del código hash es adecuado y sin orden de iteración garantizado.
Un HashSet<String> puede llevar el registro de los nombres ya procesados mientras un programa lee una secuencia de entrada más larga.
Clase LinkedHashMap
Un LinkedHashMap es un mapa cuya forma habitual con orden de inserción visita las claves en ese orden y conserva las operaciones habituales de mapa.
Reemplazar un precio almacenado conserva la posición de ese producto en un LinkedHashMap con orden de inserción.
Clase LinkedHashSet
Un LinkedHashSet almacena elementos distintos y conserva su orden de inserción, incluido el orden de primera aparición cuando se copia de una lista.
Una lista de etiquetas copiada a un LinkedHashSet pierde las repeticiones y conserva el orden en que aparecieron las etiquetas por primera vez.
Clase TreeMap
Un TreeMap mantiene las asociaciones ordenadas por sus claves y utiliza la comparación de claves para identificar una asociación existente durante una búsqueda o un reemplazo.
Un informe de recuentos de palabras en orden alfabético puede utilizar un mapa basado en árbol cuya clave menor está disponible mediante firstKey().
Clase TreeSet
Un TreeSet mantiene los elementos ordenados y utiliza su resultado de comparación para decidir si un elemento ya está presente en el conjunto.
Una comparación de miembros solo por altura hace que dos miembros distintos con la misma altura compitan por una posición del conjunto.
Clave mutable
Una clave mutable tiene datos que pueden cambiar; modificar los campos utilizados en su igualdad o código hash mientras está almacenada puede impedir la búsqueda en el mapa.
Una clave de coordenadas es más segura con campos final que con métodos modificadores que pueden cambiar su identidad mientras está almacenada.
Colección anidada
Una colección anidada almacena colecciones dentro de otra estructura, de modo que las claves externas y los miembros internos pueden seguir reglas distintas.
Un mapa de cursos ordenado puede contener listas de estudiantes en orden de inserción sin ordenar a los propios estudiantes.
Colección no modificable
Una colección no modificable rechaza modificaciones estructurales o reemplazos mediante su API, aunque los objetos que contiene pueden seguir siendo mutables.
Una lista creada con List.of debe copiarse antes de ordenarla, pero la lista no congela un objeto mutable almacenado en ella.
Comparador
Un comparador es un objeto que proporciona una regla de comparación que puede diferir del orden natural de una clase, como el orden inverso o el que no distingue mayúsculas y minúsculas.
String.CASE_INSENSITIVE_ORDER ordena una lista sin cambiar las mayúsculas y minúsculas almacenadas en cada cadena.
Conjunto
Un conjunto es una colección de elementos distintos que proporciona operaciones de pertenencia sin las posiciones indexadas que ofrece una lista.
Un conjunto de ciudades visitadas conserva una entrada por cada ciudad aunque una persona regrese varias veces.
Consistencia con equals
La consistencia con equals significa que la comparación devuelve cero exactamente cuando la igualdad devuelve true, de modo que ambas reglas identifican los mismos valores.
Un conjunto basado en árbol necesita que la comparación de miembros distinga las mismas identidades que la regla de igualdad del miembro.
Contrato del código hash
El contrato del código hash exige que los objetos iguales según equals devuelvan códigos hash iguales, y permite colisiones para objetos distintos.
Las claves de coordenadas utilizan los mismos campos x e y tanto en su comprobación de igualdad como en su método de código hash.
Copia superficial
Una copia superficial crea una estructura de colección independiente que contiene las mismas referencias a elementos, en lugar de duplicar los objetos almacenados.
Eliminar un libro de una lista copiada deja intacta la lista original, pero ambas listas pueden seguir haciendo referencia al mismo libro.
Coste de preparación (costo de preparación)
Un coste de preparación es el trabajo necesario para construir una estructura de apoyo antes de que las operaciones posteriores puedan beneficiarse de ella.
Un conjunto de pertenencia debe construirse una vez antes de muchas comprobaciones, incluyendo su construcción en el trabajo total.
Criterio de desempate
Un criterio de desempate es una comparación secundaria que se utiliza solo cuando los campos de comparación anteriores empatan, conservando su prioridad en el orden general.
Una comparación de películas por año y después por título consulta los títulos solo para películas estrenadas en el mismo año.

D

Desbordamiento de enteros
El desbordamiento de enteros ocurre cuando un resultado aritmético supera el rango de int y se desborda, lo que puede dar el signo incorrecto a las comparaciones basadas en resta.
Comparar campos int extremos con Integer.compare evita la inversión de signo que puede causar la resta.
Desempaquetado
El desempaquetado es la conversión automática que hace Java de un objeto envoltorio a un valor primitivo; intentarlo con null lanza una excepción.
Asignar a un int el resultado de una búsqueda ausente de Integer falla porque el null devuelto no se puede desempaquetar.
Diferencia de conjuntos
Una diferencia de conjuntos contiene los elementos del primer conjunto que no están en el segundo, por lo que invertir los conjuntos puede cambiar el resultado.
Eliminar los asistentes del martes de una copia del lunes encuentra a quienes asistieron solo el lunes, no a quienes asistieron solo el martes.

E

Elección de colección
La elección de colección ajusta los requisitos de posiciones, duplicados, búsqueda por clave y orden a una interfaz y una implementación adecuadas.
Un informe alfabético de recuentos y una lista de reproducción ordenada necesitan estructuras diferentes porque conservan información distinta.
Elemento distinto
Un elemento distinto es un valor considerado diferente según la regla de coincidencia de la colección, independientemente de cuántas veces aparezca.
Un mapa de frecuencias para "sun rain sun" contiene dos claves de palabras distintas, pero registra tres apariciones.
Empaquetado automático
El empaquetado automático es la conversión automática que hace Java de un valor primitivo a su objeto envoltorio correspondiente cuando se requiere un objeto.
Insertar el literal 12 en un mapa de valores Integer empaqueta automáticamente ese número para almacenarlo.
Encapsulación (encapsulamiento)
La encapsulación mantiene los datos dentro de una clase y ofrece métodos controlados para que la clase pueda mantener reglas sobre las actualizaciones y búsquedas.
Una clase de biblioteca puede mantener sus índices privados para que su método addBook los actualice conjuntamente en lugar de que los editen quienes llaman.
Entrada duplicada
Una entrada duplicada es una aparición en los datos de entrada cuyo valor igual ya se ha visto; un conjunto de valores vistos la detecta cuando add devuelve false.
En la secuencia 6, 9, 2, 9, 6, el segundo 9 es la primera llegada que repite un valor anterior.

I

Identificador único
Un identificador único distingue cada objeto dentro de los datos indexados y evita que registros separados compitan por la misma clave de mapa.
Un identificador de miembro mantiene en entradas separadas de un índice de miembros a dos personas con el mismo nombre mostrado.
Igualdad de contenido
La igualdad de contenido trata objetos separados como iguales cuando coinciden los datos elegidos, mediante una sobrescritura adecuada de equals(Object).
Dos claves de coordenadas creadas por separado pueden encontrar la misma etiqueta cuando su igualdad compara ambas coordenadas.
Igualdad por identidad
La igualdad por identidad trata los objetos como iguales solo cuando son la misma instancia; es la igualdad heredada de Object.
Sin sobrescrituras, un punto recién construido no coincide con un punto almacenado de coordenadas idénticas.
Implementación
Una implementación es una clase concreta que proporciona las operaciones de una interfaz y determina el comportamiento del objeto creado.
HashMap y TreeMap implementan Map, pero ofrecen distintas garantías sobre el orden de las claves.
Interfaz
Una interfaz declara operaciones que proporcionan las clases que la implementan, lo que permite que una variable o parámetro indique las capacidades que necesita.
Un método que acepta List<String> puede recibir un ArrayList o un LinkedList sin cambiar su firma.
Interfaz Collection
Collection es la interfaz compartida de Java para grupos de elementos, que extienden List y Set y que es independiente de la interfaz Map.
Un método de solo lectura que cuenta palabras puede aceptar una Collection<String> y recorrer tanto una lista como un conjunto.
Interfaz Comparable
Comparable es la interfaz de Java mediante la cual una clase define su orden natural implementando un método compareTo con tipo.
Una clase de miembro puede implementar Comparable<Member> para que la ordenación de listas pueda ordenar sus instancias por altura.
Interfaz Map.Entry
Un Map.Entry representa una asociación clave-valor y da acceso conjunto a su clave y su valor durante el recorrido de un mapa.
Un bucle sobre entradas puede imprimir el nombre y la puntuación de un jugador sin volver a buscar la puntuación por nombre.
Intersección
La intersección de dos conjuntos contiene solo los elementos compartidos por ambos; retainAll elimina de su receptor los valores no compartidos.
Conservar solo los nombres del martes en una copia del conjunto del lunes encuentra a las personas que asistieron ambos días.
Iterador
Un iterador sigue un recorrido por una colección y proporciona métodos para comprobar si existe un elemento siguiente y recuperarlo.
Un bucle de limpieza de existencias utiliza hasNext(), next() y remove() del iterador para eliminar cantidades cero.

Í

Índice
Un índice es un mapa que asocia una clave identificadora con un objeto y permite buscarlo por esa clave sin recorrer repetidamente una lista de objetos.
El índice por ISBN de una biblioteca puede devolver el mismo objeto de libro que también aparece en su lista de todos los libros.

L

Lista
Una List almacena elementos en una secuencia indexada que empieza en cero, permite duplicados y compara la igualdad utilizando el orden completo de los elementos.
Una lista de reproducción utiliza posiciones de lista para conservar dos apariciones de la misma canción en distintos puntos de la secuencia.
Listas paralelas
Las listas paralelas almacenan campos asociados en índices correspondientes de listas separadas, por lo que la relación depende de modificaciones estructurales coordinadas.
Eliminar el nombre de una persona sin eliminar el número del mismo índice desajusta las entradas posteriores de la agenda.

M

Mapa
Un Map asocia claves únicas con valores, permite valores repetidos y mantiene como máximo un valor asociado a cada clave en un momento dado.
Dos productos pueden estar asociados al precio 3,50 u.m. sin incumplir el requisito de que sus claves sean únicas.
Método compareTo
El método compareTo devuelve un entero negativo, cero o un entero positivo para colocar este objeto antes, empatado con o después de otro.
Un resultado de -8 coloca el objeto de la izquierda antes que el de la derecha, igual que lo haría un resultado de -1.
Método getOrDefault
El método getOrDefault devuelve el valor asociado a una clave, o el valor predeterminado proporcionado cuando no existe ninguna asociación para esa clave.
Leer un recuento ausente con cero como valor predeterminado da 0 sin crear una entrada nueva en el mapa de recuentos.
Método putIfAbsent
El método putIfAbsent almacena un valor cuando una clave no tiene una asociación con valor no nulo y, en caso contrario, conserva el valor ya asociado a esa clave.
Antes de añadir un elemento agrupado, putIfAbsent puede asegurar que su clave tenga una lista sin reemplazar una existente.
Método sobrecargado
Un método sobrecargado comparte nombre con otro método, pero utiliza parámetros diferentes, lo que permite a Java elegir una operación diferente.
Para una lista de enteros, remove(1) selecciona la eliminación por índice, mientras que remove(Integer.valueOf(1)) selecciona la eliminación por valor.
Modificación estructural
Una modificación estructural cambia el conjunto de claves de un mapa, por ejemplo, cuando se añade una asociación nueva o se elimina una existente.
Reemplazar la cantidad de una clave ya presente cambia su valor sin modificar estructuralmente el mapa.

N

Normalización de claves
La normalización de claves aplica una regla de limpieza consistente antes de almacenar y buscar, para que las formas equivalentes de entrada utilicen la misma clave de mapa.
Un contador de palabras puede convertir las unidades de entrada a minúsculas y eliminar la puntuación antes de añadir cada aparición a su mapa.

O

Orden de iteración
El orden de iteración es la secuencia en que un recorrido visita elementos o entradas; algunas implementaciones garantizan un orden y otras no.
Una búsqueda de puntuaciones empatadas necesita una regla de desempate explícita si su resultado debe ser independiente del recorrido de HashMap.
Orden natural
Un orden natural es la comparación predeterminada que proporciona una clase, como el orden numérico ascendente o el orden de cadenas basado en caracteres.
Ordenar las cadenas "20" y "3" coloca "20" primero porque los caracteres iniciales deciden su orden.
Orden por unidades de código
El orden por unidades de código compara cadenas por su primera unidad de código UTF-16 diferente y coloca primero un prefijo coincidente más corto.
En los ejemplos "7", "Bee" y "ant", el orden natural de cadenas coloca el dígito antes que las letras.
Ordenación estable
Una ordenación estable conserva el orden relativo de entrada de los elementos que se comparan como iguales según la comparación utilizada para esa ordenación.
Dos jugadores empatados por una comparación basada solo en la puntuación conservan su orden relativo anterior después de una ordenación estable de lista.
Ordenación in situ
Una ordenación in situ reorganiza la propia lista proporcionada en lugar de devolver una lista ordenada independiente para que quien llama la asigne.
Después de Collections.sort(values), la variable de lista existente muestra sus elementos en el nuevo orden.

P

Par clave-valor
Un par clave-valor vincula una clave identificadora con un valor asociado en un mapa, como un código de producto vinculado a una cantidad.
En un mapa de existencias, el par "pen" → 18 conecta un nombre de producto con la cantidad disponible actualmente.
Parámetro de tipo interfaz
Un parámetro de tipo interfaz acepta objetos mediante las operaciones que garantiza una interfaz en lugar de exigir una implementación concreta.
Un método de informes puede aceptar Map<String, Integer> mientras quienes lo llaman eligen almacenamiento basado en hash o en árbol.
Pertenencia
La pertenencia indica si un valor pertenece a un conjunto, como comprueba contains mediante la regla de coincidencia de ese conjunto.
Un programa que comprueba nombres de usuario verifica la pertenencia antes de aceptar un nombre nuevo en su conjunto de nombres ocupados.

R

Referencia compartida
Una referencia compartida permite que dos variables o entradas accedan al mismo objeto, por lo que un cambio en ese objeto es visible mediante cualquiera de las dos referencias.
Dos claves de curso a las que se asigna un mismo objeto de lista mostrarán ambas a un estudiante añadido mediante solo una de esas claves.

S

Sintaxis de diamante
La sintaxis de diamante utiliza signos angulares vacíos en un constructor para que Java pueda inferir sus argumentos de tipo a partir de la declaración que lo rodea.
En HashMap<String, Integer> m = new HashMap<>();, el diamante evita repetir los dos tipos.
Subconjunto
Un subconjunto tiene todos sus elementos en otro conjunto, que puede contener elementos adicionales; a.containsAll(b) comprueba si b está contenido en a.
Un grupo seleccionado es un subconjunto de un conjunto de asistentes cuando cada persona seleccionada aparece en la lista de ese evento.
Suma acumulada
Una suma acumulada es una cantidad acumulada que se actualiza sumando cada nueva contribución a la cantidad ya almacenada.
Un mapa de gastos lee el total anterior de una categoría, suma la siguiente cantidad y almacena el resultado incrementado.

T

Tabla de consulta
Una tabla de consulta asocia códigos o nombres con datos que un programa recupera al procesar otra tarea.
Un programa que calcula pedidos lee los precios de los productos de una tabla antes de sumar la contribución de cada producto.
Tabla de frecuencias
Una tabla de frecuencias vincula cada elemento distinto con su número de apariciones, normalmente mediante claves de mapa para los elementos y valores enteros para los recuentos.
Un mapa de recuento de palabras distingue el número de palabras diferentes del número total de apariciones de palabras.
Tiempo constante
El tiempo constante describe un trabajo que se mantiene aproximadamente independiente del número de elementos; las operaciones básicas basadas en hash tienen este coste en promedio si el cálculo del código hash es adecuado.
Leer una posición de un ArrayList no requiere recorrer todas las posiciones anteriores de esa lista.
Tiempo lineal
El tiempo lineal describe un trabajo que puede crecer en proporción al número de elementos, como cuando una búsqueda puede examinar toda la colección.
Las comprobaciones repetidas de pertenencia en una lista larga pueden requerir recorrer repetidamente los mismos nombres almacenados.
Tiempo logarítmico
El tiempo logarítmico describe un trabajo que crece lentamente con el número de elementos, como en los costes garantizados de las búsquedas básicas en mapas y conjuntos basados en árboles.
Un mapa basado en árbol mantiene las claves ordenadas y evita un recorrido completo para cada búsqueda habitual por clave.
Tipo declarado
El tipo declarado de una variable determina a qué métodos permite llamar el compilador mediante esa variable, incluso cuando su objeto tiene métodos adicionales.
Un ArrayList almacenado en una variable List no permite acceder a ensureCapacity mediante esa variable.
Transitividad
La transitividad exige que un orden coloque a antes que c siempre que coloque a antes que b y b antes que c, para mantener la coherencia de las comparaciones.
Comparar los campos en un orden fijo de prioridad evita un ciclo en el que cada uno de tres objetos precede a otro.
Truncamiento
El truncamiento descarta una fracción decimal cuando un valor se convierte explícitamente a int, lo que puede convertir en cero una pequeña diferencia de comparación distinta de cero.
Convertir explícitamente a int la diferencia entre los precios 2,7 y 2,2 produce un falso empate en lugar de una comparación positiva.

U

Unión
La unión de dos conjuntos contiene todos los elementos presentes en cualquiera de ellos; addAll de Java la forma modificando el conjunto receptor.
Copiar el conjunto de asistentes del lunes y añadir el del martes da todas las personas que asistieron al menos uno de los días.

V

Vista de colección
Una vista de colección permite acceder a una parte de otra estructura mediante una interfaz de colección, con cambios vinculados a la estructura subyacente.
Eliminar un producto mediante el conjunto de claves del mapa de existencias elimina la entrada correspondiente del propio mapa.

Sobre esta unidad

Por StudeliInformar de un error

Crea tus propios Materiales de Estudio

Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.

Comenzar