Mapas
Mapas (Interfaz Map)
Los mapas en Java van a ser una estructura que almacene objetos a partir de una clave. Se introducen en las colecciones de objetos pero es la única que no depende de Collection. Ver -> diagrama
Por tanto para Java no es una colección como tal, pero el concepto es el mismo. Almacenar y organizar los objetos de un programa. Aspectos importantes:
- Las claves deben ser únicas -> K
- Los objetos (V) se almacenarán y se recuperán a partir de la clave.
- Se basa en una estructura dinámica de tipo diccionario cuyos nodos, o entradas, son instancias de la clase interna Map.Entry<K,V>
Existen tres implementaciones principales de Map:
- HashMap: permite valores nulos y no es predecible el orden de los objetos (tablas Hash). Conveniente para inserciones y recuperaciones.
- LinkedHashMap: permite valores nulos y si es predecible el orden de los objetos. Si se va iterar con frecuencia es la mejor opción.
- TreeMap: no permite valores nulos y si es predecible el orden de los objetos. El más usado, buen rendimiento en búsquedas, acceso y eliminación.
Los Mapas son muy utilizados cuando queremos velocidad de acceso a los objetos y actualizarlos.
Funciones básicas de Map
Creación e inserción de elementos
Método V put(K key, V value): añade o reemplaza la entrada del mapa de la clave K. Devuelve el objeto antiguo si la entrada existe, en caso contrario null. Ejemplo:
Map<Integer, String> mapHttpErrors = new HashMap<>();
mapHttpErrors.put(200, "OK");
mapHttpErrors.put(303, "See Other");
mapHttpErrors.put(404, "Not Found");
mapHttpErrors.put(500, "Internal Server Error");
System.out.println(mapHttpErrors);
Para volcar un mapa a otro tenemos el método putAll o también el constructor de Map:
Map<Integer, String> mapErrors = new HashMap<>(mapHttpErrors);
Recuperación de objetos
Método principal es el V get(Value k): devuelve el objeto de la clave, null si no existe Otros métodos muy prácticos son el size(), isEmpty(), y por supuesto:
- boolean containsKey(Object k) Devuelve true si existe una entrada de clave k o false si no existe.
- boolean containsValue(Object v) Devuelve true si existe una entrada de valor v o false si no existe.
Ejemplo:
String status301 = mapHttpErrors.get(301);
System.out.println("301: " + status301);
if (mapHttpErrors.containsKey("200")) {
System.out.println("Http status 200");
}
if (mapHttpErrors.containsValue("OK")) {
System.out.println("Found status OK");
}
String status301 = mapHttpErrors.get(301);
System.out.println("301: " + status301);
Actualizar o eliminar
Para eliminar tenemos:
- remove(Object key): elimina la entrada al mapa, si existe devuelve el objeto eliminado, sino null.
Para reemplazar:
- replace(Object Key, Object Value): cambia un objeto por otro a partir de la clave.
Recorrer un Map
Hay muchas formas para recorrer un mapa: Método keySet() y usando un Iterator:
Map<String, String> mapCountryCodes = new HashMap<>();
mapCountryCodes.put("1", "USA");
mapCountryCodes.put("44", "United Kingdom");
mapCountryCodes.put("33", "France");
mapCountryCodes.put("81", "Japan");
Set<String> setCodes = mapCountryCodes.keySet();
Iterator<String> iterator = setCodes.iterator();
while (iterator.hasNext()) {
String code = iterator.next();
String country = mapCountryCodes.get(code);
System.out.println(code + " => " + country);
}
Método values() con el cual obtenemos una colección:
Collection<String> countries = mapCountryCodes.values();
for (String country : countries) {
System.out.println(country);
}
El método entrySet(), nos devuelve un Set para recorrerlo es necesario Map.Entry:
Set<Map.Entry<String, String>> entries = mapCountryCodes.entrySet();
for (Map.Entry<String, String> entry : entries) {
String code = entry.getKey();
String country = entry.getValue();
System.out.println(code + " => " + country);
}
Y por último con lambda y el forEach es muy cómodo:
mapCountryCodes.forEach(
(code, country) -> System.out.println(code + " => " + country));
Ejemplo:
import java.util.*;
class MapaDemo2 {
public static void main(String[] args) {
LinkedHashMap<Integer, String> map = new LinkedHashMap<>();
map.put(1, "uno"); map.put(2, "dos"); map.put(3, "tres");
System.out.println("Claves = " + map.keySet()); // set-vista de claves
System.out.println("Valores = " + map.values()); // set-vista de valores
System.out.println("Entradas = " + map.entrySet()); // set-vista de entradas
Set<Integer> claves = map.keySet();
for(Integer k: claves) {
System.out.println("clave: " + k + "-> val: " + map.get(k)); }
Set<Map.Entry<Integer, String>> entradas = map.entrySet();
for(Map.Entry<Integer, String> e: entradas) {
System.out.println("clave: " + e.getKey() + "-> val: " + e.getValue());
}
}
}
Ejercicio 1
Tenemos la siguiente tabla de latitudes/longitudes de ciudades nacionales e internacionales:
CIUDAD | LATITUD | LONGITUD |
---|---|---|
LUGO | 43.01 N | 7.33 O |
BARCELONA | 41.23 N | 2.11 E |
MADRID | 40.24 N | 3.41 O |
LIMA | 12.03 S | 77.03 0 |
Las coordenadas son obligatoriamente objetos de la siguiente clase, a la que añadirás los métodos necesarios class Coordenadas{ private latitud; private longitud; } Los datos de la tabla anterior se almacena obligatoriamente en un hashmap cuya clave es la capital, y el objeto que almacena es la coordenada. Tu programa debe:
- Insertar los datos.
- Recorrer el mapa (prueba de varias maneras).
- Consultar y eliminar objetos.
Ejercicio 2
Crea una pequeña guía telefónica usando TreeMap. Los valores serán nombre y telefono. Funcionalidades:
- Obtener el número a partir del nombre.
- Actualizar número.
- Mostrar todas las entradas de la guía.
Ejercicio 3
Tenemos almacenados en un TreeMap unos alumnos (nombre y nota media), la clave del mapa es el nombre del alumno. Nos piden que se almacene los alumnos por orden natural alfabético del alumno. Más tarde nos piden justo el orden inverso (prueba Collections.reverseOrder()) en el constructor del Treemap. También prueba los métodos firstkey(), lastkey() y headMap(), ¿que hacen?.