Saltearse al contenido

Java Maps

Introducción

Los Maps en Java son estructuras de datos que representan una colección de pares clave-valor. Implementan la interfaz java.util.Map y son extremadamente útiles para almacenar y recuperar datos de manera eficiente.

Creación de un Map

Existen varias implementaciones de Map en Java. Las más comunes son HashMap y TreeMap.

1
Map<String, Integer> mapaNombresEdades = new HashMap<>();
2
Map<Integer, String> mapaCodigosProductos = new TreeMap<>();

Es una buena práctica utilizar genéricos para especificar los tipos de las claves y valores. Esto es, definir el tipo de dato que se almacenará en el Map.

Inserción de elementos

Para agregar elementos a un Map, utilizamos el método put():

1
Map<String, List<String>> mapaEstudiantesCursos = new HashMap<>();
2
3
List<String> cursosAna = new ArrayList<>();
4
cursosAna.add("Matemáticas");
5
cursosAna.add("Física");
6
mapaEstudiantesCursos.put("Ana", cursosAna);
7
8
List<String> cursosCarlos = new ArrayList<>();
9
cursosCarlos.add("Literatura");
10
cursosCarlos.add("Historia");
11
mapaEstudiantesCursos.put("Carlos", cursosCarlos);

Inserción de múltiples elementos

Para insertar todos los elementos de un Map en otro, usamos putAll():

1
Map<String, Double> preciosProductosA = new HashMap<>();
2
preciosProductosA.put("Laptop", 999.99);
3
preciosProductosA.put("Smartphone", 599.99);
4
5
Map<String, Double> preciosProductosB = new HashMap<>();
6
preciosProductosB.putAll(preciosProductosA);
7
preciosProductosB.put("Tablet", 299.99);

Obtención de elementos

Para obtener un valor asociado a una clave, usamos el método get():

1
List<String> cursosAna = mapaEstudiantesCursos.get("Ana");
2
if (cursosAna != null && !cursosAna.isEmpty()) {
3
String primerCursoAna = cursosAna.get(0);
4
System.out.println("Primer curso de Ana: " + primerCursoAna);
5
}

Valor por defecto

Si no estamos seguros de que una clave exista, podemos usar getOrDefault(), que nos permite especificar un valor por defecto en caso de que la clave no exista:

1
List<String> cursosJuan = mapaEstCursos.getOrDefault("Juan", new ArrayList<>());
2
System.out.println("Cursos de Juan: " + cursosJuan);

Aquí podríamos realizar alguna acción si la lista de cursos está vacía, como agregar un mensaje de error.

Verificación de contenido

Para verificar si un Map contiene una clave o un valor específico:

1
boolean contieneAna = mapaEstudiantesCursos.containsKey("Ana");
2
3
boolean contieneFisica = false;
4
for (List<String> cursos : mapaEstudiantesCursos.values()) {
5
if (cursos.contains("Física")) {
6
contieneFisica = true;
7
break;
8
}
9
}

Iteración sobre un Map

Existen varias formas de iterar sobre un Map:

Usando entrySet()

1
for (Map.Entry<String, List<String>> entrada : mapaEstudiantesCursos.entrySet()) {
2
System.out.println(entrada.getKey() + " está inscrito en: " + entrada.getValue());
3
}

Usando keySet() y valores

1
for (String estudiante : mapaEstudiantesCursos.keySet()) {
2
List<String> cursos = mapaEstudiantesCursos.get(estudiante);
3
System.out.println(estudiante + " está tomando " + cursos.size() + " cursos");
4
}

Eliminación de elementos

Para eliminar un elemento específico:

1
List<String> cursosEliminados = mapaEstudiantesCursos.remove("Carlos");

Para eliminar todos los elementos de un Map:

1
mapaEstudiantesCursos.clear();

Reemplazo de valores

El método replace() solo reemplaza el valor si la clave ya existe:

1
List<String> nuevosCursosAna = new ArrayList<>();
2
nuevosCursosAna.add("Química");
3
nuevosCursosAna.add("Biología");
4
mapaEstudiantesCursos.replace("Ana", nuevosCursosAna);

Además de reemplazar, este método también devuelve el valor anterior asociado a la clave.

Operaciones adicionales

Tamaño del Map

1
int numeroEstudiantes = mapaEstudiantesCursos.size();

Verificar si está vacío

1
boolean estaVacio = mapaEstudiantesCursos.isEmpty();

Ejemplo práctico

Veamos un ejemplo más complejo que combina varias de estas operaciones:

1
import java.util.*;
2
3
public class SistemaCalificaciones {
4
private Map<String, Map<String, Double>> calificacionesEstudiantes;
5
6
public SistemaCalificaciones() {
7
calificacionesEstudiantes = new HashMap<>();
8
}
9
10
public void agregarCalificacion(String estudiante, String materia, Double calificacion) {
11
// Si no existe el estudiante, se crea un nuevo Map para sus calificaciones
12
if (!calificacionesEstudiantes.containsKey(estudiante)) {
13
calificacionesEstudiantes.put(estudiante, new HashMap<>());
14
}
15
// Se agrega la calificación al Map correspondiente
16
calificacionesEstudiantes.get(estudiante).put(materia, calificacion);
17
}
18
19
public Double obtenerPromedio(String estudiante) {
20
Map<String, Double> calificaciones = calificacionesEstudiantes.get(estudiante);
21
if (calificaciones == null || calificaciones.isEmpty()) {
22
return 0.0;
23
}
24
double suma = 0.0;
25
int contador = 0;
26
for (Double calificacion : calificaciones.values()) {
27
suma += calificacion;
28
contador++;
29
}
30
return suma / contador;
31
}
32
33
public void imprimirCalificaciones() {
34
for (String estudiante : calificacionesEstudiantes.keySet()) {
35
System.out.println(estudiante + ":");
36
Map<String, Double> calificaciones = calificacionesEstudiantes.get(estudiante);
37
for (String materia : calificaciones.keySet()) {
38
Double calificacion = calificaciones.get(materia);
39
System.out.println(" " + materia + ": " + calificacion);
40
}
41
System.out.println(" Promedio: " + obtenerPromedio(estudiante));
42
}
43
}
44
45
public static void main(String[] args) {
46
SistemaCalificaciones sistema = new SistemaCalificaciones();
47
48
sistema.agregarCalificacion("Ana", "Matemáticas", 9.5);
49
sistema.agregarCalificacion("Ana", "Física", 8.7);
50
sistema.agregarCalificacion("Carlos", "Literatura", 7.8);
51
sistema.agregarCalificacion("Carlos", "Historia", 8.9);
52
53
sistema.imprimirCalificaciones();
54
}
55
}

Detalles de funcionamiento del ejemplo

El Sistema de Calificaciones implementado en este ejemplo utiliza una estructura de datos basada en Maps anidados para gestionar las calificaciones de los estudiantes. Con los componentes principales:

  1. Estructura de datos:

    1
    private Map<String, Map<String, Double>> calificacionesEstudiantes;
    • Es un Map donde la clave es el nombre del estudiante (String).
    • El valor es otro Map que representa las calificaciones del estudiante.
    • En el Map interno, la clave es el nombre de la materia (String) y el valor es la calificación (Double).
  2. Métodos principales:

    a. agregarCalificacion:

    • Verifica si el estudiante ya existe en el Map principal.
    • Si no existe, crea un nuevo Map para ese estudiante.
    • Agrega la calificación al Map del estudiante.

    b. obtenerPromedio:

    • Recupera el Map de calificaciones del estudiante.
    • Calcula el promedio sumando todas las calificaciones y dividiendo por el número de materias.

    c. imprimirCalificaciones:

    • Itera sobre todos los estudiantes en el Map principal.
    • Para cada estudiante, itera sobre sus materias y calificaciones.
    • Imprime cada calificación y calcula el promedio.
  3. Flujo de ejecución:

    • Se crea una instancia de SistemaCalificaciones.
    • Se agregan calificaciones para diferentes estudiantes y materias.
    • Se llama al método imprimirCalificaciones para mostrar todos los datos.

Con respecto a TreeMap, esta implementación ordena las claves de manera natural o según un comparador personalizado. Por otro lado, HashMap no garantiza ningún orden específico. Esto lo veremos al iterar sobre los elementos de un Map.