Saltar al contenido principal

Set y Map

Una lista conserva una secuencia, incluso con duplicados. Otros problemas piden garantías distintas: etiquetas únicas o productos localizados por código.

Set: unicidad​

Set<String> etiquetas = new HashSet<>();
etiquetas.add("java");
etiquetas.add("docker");
System.out.println(etiquetas.add("java")); // false

HashSet rechaza duplicados y no garantiza orden. Ofrece add, contains, remove y size. Se recorre sin índices. Elige Set cuando la unicidad sea parte del modelo; si necesitas posiciones o duplicados, usa List.

Map: clave y valor​

Map<String, Integer> stock = new HashMap<>();
stock.put("T-01", 4);
stock.put("R-02", 7);
stock.put("T-01", 5);

La clave es única: el segundo put para T-01 sustituye el valor anterior. Claves y valores pueden tener tipos diferentes. get, remove, containsKey, getOrDefault y size cubren las operaciones habituales.

HashMap tampoco garantiza orden. Map no extiende Collection: almacena asociaciones, no elementos aislados.

Recorrer un Map​

for (String codigo : stock.keySet()) System.out.println(codigo);
for (Integer cantidad : stock.values()) System.out.println(cantidad);

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

entrySet() resulta adecuado cuando necesitamos clave y valor juntos.

Igualdad en estructuras hash​

HashSet y las claves de HashMap usan hashCode() para localizar candidatos y equals() para confirmar la igualdad. Con objetos propios debemos expresar la identidad lógica.

import java.util.Objects;

class Producto {
private final String codigo;
private String nombre;

public Producto(String codigo, String nombre) {
this.codigo = codigo;
this.nombre = nombre;
}

@Override
public boolean equals(Object otro) {
if (this == otro) return true;
if (!(otro instanceof Producto)) return false;
Producto producto = (Producto) otro;
return Objects.equals(codigo, producto.codigo);
}

@Override
public int hashCode() {
return Objects.hash(codigo);
}
}

Dos productos con el mismo código representan la misma identidad lógica. Regla práctica: si sobrescribes equals, sobrescribe también hashCode de forma coherente. Evita cambiar mientras está almacenado el dato que participa en ambos.

Ejemplo completo​

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

class Producto {
private final String codigo;
private final String nombre;
public Producto(String codigo, String nombre) { this.codigo = codigo; this.nombre = nombre; }
@Override public boolean equals(Object otro) {
if (this == otro) return true;
if (!(otro instanceof Producto)) return false;
Producto p = (Producto) otro;
return Objects.equals(codigo, p.codigo);
}
@Override public int hashCode() { return Objects.hash(codigo); }
@Override public String toString() { return codigo + " - " + nombre; }
}

public class SetMapDemo {
public static void main(String[] args) {
Set<Producto> productos = new HashSet<>();
System.out.println(productos.add(new Producto("T-01", "Teclado")));
System.out.println(productos.add(new Producto("T-01", "Otro teclado")));

Map<String, Integer> stock = new HashMap<>();
stock.put("T-01", 4);
stock.put("T-01", 5);
for (Map.Entry<String, Integer> entrada : stock.entrySet()) {
System.out.println(entrada.getKey() + ": " + entrada.getValue());
}
}
}

Errores habituales​

  • Usar List y comprobar duplicados manualmente cuando la intención es unicidad.
  • Esperar orden de HashSet o HashMap.
  • Sobrescribir equals sin hashCode.
  • Usar como clave un dato mutable que participa en la igualdad.
  • Confundir una clave ausente con un valor presente igual a null.

Practica: recuento de votos​

Enunciado y criterios​

Cuenta votos por opción con Map<String, Integer> usando getOrDefault. Conserva también los nombres de votantes únicos en un Set.

Solución​

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class VotosDemo {
public static void main(String[] args) {
String[] opciones = {"A", "B", "A", "A"};
Map<String, Integer> votos = new HashMap<>();
for (String opcion : opciones) {
votos.put(opcion, votos.getOrDefault(opcion, 0) + 1);
}
Set<String> votantes = new HashSet<>();
votantes.add("ana");
votantes.add("ana");
votantes.add("leo");

for (Map.Entry<String, Integer> entrada : votos.entrySet()) {
System.out.println(entrada.getKey() + ": " + entrada.getValue());
}
System.out.println("Votantes únicos: " + votantes.size());
}
}

Cada estructura expresa una garantía diferente: Map asocia opción y contador; Set asegura unicidad.