Todo se puede aprender
...si se quiere.
Home » , » Ejemplo de Interfaz Map en Java

Ejemplo de Interfaz Map en Java

interfaz map
La Interface Map (java.io.Map) en Java, nos permite representar una estructura de datos para almacenar pares “clave/valor”; de tal manera que para una clave solamente tenemos un valor. Esta estructura de datos también es conocida en otros lenguajes de programación como “Diccionarios”, aunque en cada lenguajes esta estructura de datos tiene sus matices. Los Maps en java tienen implementada por debajo toda la teoría de las estructuras de datos de los Arboles (AVL, B, B+, B*) por tanto permiten añadir, eliminar y modificar elementos de forma trasparente para el programador. Antes de pasar a explicar el manejo de los Map, dejamos un enlace al JavaDoc, pulsando AQUI.

Los principales métodos para trabajar con los Map son los siguientes:

// Declaración de un Map (un HashMap) con clave "Integer" y Valor "String". Las claves pueden ser de cualquier tipo de objetos, aunque los más utilizados como clave son los objetos predefinidos de Java como String, Integer, Double ... !!!!CUIDADO los Map no permiten datos atómicos
Map<Integer, String> nombreMap = new HashMap<Integer, String>();
nombreMap.size(); // Devuelve el numero de elementos del Map
nombreMap.isEmpty(); // Devuelve true si no hay elementos en el Map y false si si los hay
nombreMap.put(K clave, V valor); // Añade un elemento al Map
nombreMap.get(K clave); // Devuelve el valor de la clave que se le pasa como parámetro o 'null' si la clave no existe
nombreMap.clear(); // Borra todos los componentes del Map
nombreMap.remove(K clave); // Borra el par clave/valor de la clave que se le pasa como parámetro
nombreMap.containsKey(K clave); // Devuelve true si en el map hay una clave que coincide con K
nombreMap.containsValue(V valor); // Devuelve true si en el map hay un Valor que coincide con V
nombreMap.values(); // Devuelve una "Collection" con los valores del Map

Otro elemento importante a la hora de trabajar con los Maps (aunque no lo es tanto como a la hora de trabajar con los ArrayList) son los “Iteradores” (Iterator). Los Iteradores sirven para recorrer los Map y poder trabajar con ellos. Los Iteradores solo tienen tres métodos que son el “hasNext()” para comprobar que siguen quedando elementos en el iterador, el“next()”  para que nos de el siguiente elemento del iterador; y el “remove()” que sirve para eliminar el elemento del Iterador. En realidad se puede prescindir de los iteradores para trabajar con los Map ya que la gran ventaja de los Map frente a los ArrayList, es que estos tienen una clave asociada al objeto y se les puede buscar por la clave, aunque nunca esta de más saber utilizar los iteradores para manejar los Map.

Antes de seguir con ejemplos, os habréis dado cuenta que hemos empezado la entrada diciendo que Map es una Interface y por tanto se deben de implementar los métodos de la interface. Java ya tiene implementadas varias “clases Map”. No vamos a explicar todas, pero si las tres que consideramos más importantes y útiles para que veáis la diferencia como son la clase “HashMap“, “TreeMap” y “LinkedHashMap“. La diferencia principal de estas 3 clases es la forma o el orden en las que guardan los valores en el Map. Si disteis en la carrera de Ingeniería Informática (o derivados) toda esa teoría de arboles (que no vamos a recordar aquí), veríais que la gran diferencia entre los arboles AVL, B, B+ y B* es la forma en la que guardan los datos para después optimizar las altas, bajas, modificaciones y consultas de los “valores”. Pues bien toda esa teoría en esta entrada para nosotros es trasparente, pero esta bien que veamos estas tres clases para que en función de vuestro problema elijáis la mejor clase:
  • HashMap: Los elementos que inserta en el map no tendrán un orden específico. No aceptan claves duplicadas ni valores nulos.
  • TreeMap: El Mapa lo ordena de forma “natural”. Por ejemplo, si la clave son valores enteros (como luego veremos), los ordena de menos a mayor.
  • LinkedHashMap: Inserta en el Map los elementos en el orden en el que se van insertando; es decir, que no tiene una ordenación de los elementos como tal, por lo que esta clase realiza las búsquedas de los elementos de forma más lenta que las demás clases.

Visto esto vamos a poner un ejemplo de estas 3 clases y como ordena los elementos. Para este ejemplo vamos a tener un Map en el que la clave va a ser el dorsal de los jugadores de fútbol de la selección española que jugaron de titulares la final de la copa del mundo de 2010, y su valor va a ser su nombre.

Con un HashMap

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "Casillas"); map.put(15, "Ramos");
map.put(3, "Pique"); map.put(5, "Puyol");
map.put(11, "Capdevila"); map.put(14, "Xabi Alonso");
map.put(16, "Busquets"); map.put(8, "Xavi Hernandez");
map.put(18, "Pedrito"); map.put(6, "Iniesta");
map.put(7, "Villa");

// Imprimimos el Map con un Iterador
Iterator it = map.keySet().iterator();
while(it.hasNext()){
  Integer key = it.next();
  System.out.println("Clave: " + key + " -> Valor: " + map.get(key));
}

El resultado que tenemos es el siguiente, en el que vemos que nos da los objetos sin un “orden lógico”:

Clave: 16 -> Valor: Busquets
Clave: 1  -> Valor: Casillas
Clave: 18 -> Valor: Pedrito
Clave: 3  -> Valor: Pique
Clave: 5  -> Valor: Puyol
Clave: 6  -> Valor: Iniesta
Clave: 7  -> Valor: Villa
Clave: 8  -> Valor: Xavi Hernandez
Clave: 11 -> Valor: Capdevila
Clave: 14 -> Valor: Xabi Alonso
Clave: 15 -> Valor: Ramos

Con un TreeMap

Map<Integer, String> treeMap = new TreeMap<Integer, String>();
treeMap.put(1, "Casillas"); treeMap.put(15, "Ramos");
treeMap.put(3, "Pique"); treeMap.put(5, "Puyol");
treeMap.put(11, "Capdevila"); treeMap.put(14, "Xabi Alonso");
treeMap.put(16, "Busquets"); treeMap.put(8, "Xavi Hernandez");
treeMap.put(18, "Pedrito"); treeMap.put(6, "Iniesta");
treeMap.put(7, "Villa");

// Imprimimos el Map con un Iterador que ya hemos instanciado anteriormente
it = treeMap.keySet().iterator();
while(it.hasNext()){
  Integer key = it.next();
  System.out.println("Clave: " + key + " -> Valor: " + treeMap.get(key));
}

El resultado que tenemos es el siguiente en el que vemos que nos ordena los objetos por clave en “orden natural”:

Clave: 1  -> Valor: Casillas
Clave: 3  -> Valor: Pique
Clave: 5  -> Valor: Puyol
Clave: 6  -> Valor: Iniesta
Clave: 7  -> Valor: Villa
Clave: 8  -> Valor: Xavi Hernandez
Clave: 11 -> Valor: Capdevila
Clave: 14 -> Valor: Xabi Alonso
Clave: 15 -> Valor: Ramos
Clave: 16 -> Valor: Busquets
Clave: 18 -> Valor: Pedrito

Con un LinkedHashMap

Map<Integer, String> linkedHashMap = new LinkedHashMap<Integer, String>();
linkedHashMap.put(1, "Casillas"); linkedHashMap.put(15, "Ramos");
linkedHashMap.put(3, "Pique"); linkedHashMap.put(5, "Puyol");
linkedHashMap.put(11, "Capdevila"); linkedHashMap.put(14, "Xabi Alonso");
linkedHashMap.put(16, "Busquets"); linkedHashMap.put(8, "Xavi Hernandez");
linkedHashMap.put(18, "Pedrito"); linkedHashMap.put(6, "Iniesta");
linkedHashMap.put(7, "Villa");

// Imprimimos el Map con un Iterador que ya hemos instanciado anteriormente
it = linkedHashMap.keySet().iterator();
while(it.hasNext()){
  Integer key = it.next();
  System.out.println("Clave: " + key + " -> Valor: " + linkedHashMap.get(key));
}

El resultado que tenemos es el siguiente en el que vemos que nos ordena los objetos tal y como los hemos ido introduciendo:

Clave: 1  -> Valor: Casillas
Clave: 15 -> Valor: Ramos
Clave: 3  -> Valor: Pique
Clave: 5  -> Valor: Puyol
Clave: 11 -> Valor: Capdevila
Clave: 14 -> Valor: Xabi Alonso
Clave: 16 -> Valor: Busquets
Clave: 8  -> Valor: Xavi Hernandez
Clave: 18 -> Valor: Pedrito
Clave: 6  -> Valor: Iniesta
Clave: 7  -> Valor: Villa

Una vez que hemos visto las diferencias entre unas clases de Map y otras, vamos a ver el funcionamiento de los métodos que hemos mencionado al principio:

System.out.println("********* Trabajando con los métodos de Map *********");
System.out.println("Mostramos el numero de elementos que tiene el TreeMap: treeMap.size() = "+treeMap.size());
System.out.println("Vemos si el TreeMap esta vacio : treeMap.isEmpty() = "+treeMap.isEmpty());
System.out.println("Obtenemos un elemento del Map pasandole la clave 6: treeMap.get(6) = "+treeMap.get(6));
System.out.println("Borramos un elemento del Map el 18 (porque fue sustituido): treeMap.remove(18)"+treeMap.remove(18));
System.out.println("Vemos que pasa si queremos obtener la clave 18 que ya no existe: treeMap.get(18) = "+treeMap.get(18));
System.out.println("Vemos si existe un elemento con la clave 18: treeMap.containsKey(18) = "+treeMap.containsKey(18));
System.out.println("Vemos si existe un elemento con la clave 1: treeMap.containsKey(1) = "+treeMap.containsKey(1));
System.out.println("Vemos si existe el valo 'Villa' en el Map: treeMap.containsValue(\"Villa\") = "+treeMap.containsValue("Villa"));
System.out.println("Vemos si existe el valo 'Ricardo' en el Map: treeMap.containsValue(\"Ricardo\") = "+treeMap.containsValue("Ricardo"));
System.out.println("Borramos todos los elementos del Map: treeMap.clear()");treeMap.clear();
System.out.println("Comprobamos si lo hemos eliminado viendo su tamaño: treeMap.size() = "+treeMap.size());
System.out.println("Lo comprobamos tambien viendo si esta vacio treeMap.isEmpty() = "+treeMap.isEmpty());

Como salida para todos los métodos ejecutados obtendremos la siguiente:

********* Trabajando con los métodos de Map *********
Mostramos el numero de elementos que tiene el TreeMap: treeMap.size() = 11
Vemos si el TreeMap esta vacio : treeMap.isEmpty() = false
Obtenemos un elemento del Map pasandole la clave 6: treeMap.get(6) = Iniesta
Borramos un elemento del Map el 18 (porque fue sustituido): treeMap.remove(18)Pedrito
Vemos que pasa si queremos obtener la clave 18 que ya no existe: treeMap.get(18) = null
Vemos si existe un elemento con la clave 18: treeMap.containsKey(18) = false
Vemos si existe un elemento con la clave 1: treeMap.containsKey(1) = true
Vemos si existe el valo 'Villa' en el Map: treeMap.containsValue("Villa") = true
Vemos si existe el valo 'Ricardo' en el Map: treeMap.containsValue("Ricardo") = false
Borramos todos los elementos del Map: treeMap.clear()
Comprobamos si lo hemos eliminado viendo su tamaño: treeMap.size() = 0
Lo comprobamos tambien viendo si esta vacio treeMap.isEmpty() = true

Otra de las cosas más útiles al trabajar con los Map es el recorrerlos como si fuese un ArrayList, y eso lo conseguimos de la siguiente forma. Si queremos obtener los pares clave/valor o solo las claves o los valores por separado (cuidado ahora estamos trabajando con el LinkedHashMap del ejemplo):

System.out.println("Foreach: Forma alternativa para recorrer los Map mostrando la Clave y el valor:");
for (Entry<Integer, String> jugador : linkedHashMap.entrySet()){
Integer clave = jugador.getKey();
String valor = jugador.getValue();
System.out.println(clave+"  ->  "+valor);
}

Como salida a este fragmento de código tenemos lo siguiente (que son a los jugadores por orden de inserción en el Map):

Foreach: Forma alternativa para recorrer los Map mostrando la Clave y el valor:
1  ->  Casillas
15 ->  Ramos
3  ->  Pique
5  ->  Puyol
11 ->  Capdevila
14 ->  Xabi Alonso
16 ->  Busquets
8  ->  Xavi Hernandez
18 ->  Pedrito
6  ->  Iniesta
7  ->  Villa

Como vemos, lo que hace este “foreach” es ir dándonos uno a uno cada par clave valor. Por tanto, si obtuviésemos solo el valor, tendríamos el mismo efecto que si estuviésemos trabajando con ArrayList o Colecciones.

Visto las 3 clases más utilizadas del los Map y los métodos más importantes, vamos a poner un ejemplo más de como trabajar con los Map. Pero en esta ocasión el valor no será un objeto predefinido de Java, sino que será un objeto de la clase “JugadorSeleccion” que mostramos a continuación:

class JugadorSeleccion {

private int dorsal;
private String nombre;
private String demarcacion;

public JugadorSeleccion() {
}

public JugadorSeleccion(int dorsal, String nombre, String demarcación) {
this.dorsal = dorsal;
this.nombre = nombre;
this.demarcacion = demarcación;
}

public int getDorsal() {
return dorsal;
}

public void setDorsal(int dorsal) {
this.dorsal = dorsal;
}

public String getNombre() {
return nombre;
}

public void setNombre(String nombre) {
this.nombre = nombre;
}

public String getDemarcación() {
return demarcacion;
}

public void setDemarcación(String demarcación) {
this.demarcacion = demarcación;
}

@Override
public String toString() {
return this.dorsal+"  --  "+this.nombre+"  --  "+this.demarcacion;
}

}

En este ejemplo nos vamos a crear un TreeMap en la que la clave será el nombre del jugador y el valor será un objeto de la clase “JugadorSeleccion”. El TreeMap lo declaramos de la siguiente forma y metemos en él los siguientes objetos:

System.out.println("********* TreeMap con Objetos y como Clave un String *********");
Map <String, JugadorSeleccion> jugadores = new TreeMap<String, JugadorSeleccion>();
jugadores.put("Casillas", new JugadorSeleccion(1, "Casillas", "Portero"));
jugadores.put("Ramos", new JugadorSeleccion(15, "Ramos", "Lateral Derecho"));
jugadores.put("Pique", new JugadorSeleccion(13, "Pique", "Central"));
jugadores.put("Puyol", new JugadorSeleccion(5, "Puyol", "Central"));
jugadores.put("Capdevila", new JugadorSeleccion(11, "Capdevila", "Lateral Izquierdo"));
jugadores.put("Xabi", new JugadorSeleccion(14, "Xabi Alonso", "Medio Centro"));
jugadores.put("Busquets", new JugadorSeleccion(16, "Busquets", "Medio Centro"));
jugadores.put("Xavi", new JugadorSeleccion(8, "Xavi Hernandez", "Centro Campista"));
jugadores.put("Pedrito", new JugadorSeleccion(18, "Pedrito", "Interior Izquierdo"));
jugadores.put("Iniesta", new JugadorSeleccion(6, "Iniesta", "Interior Derecho"));
jugadores.put("Villa", new JugadorSeleccion(7, "Villa", "Delantero"));

Si hacemos un “foreach” de este TreeMap, vamos a ver que el Map va a estar ordenado por orden alfabético de la clave. Es decir, por el nombre de los jugadores:

for (Entry<String, JugadorSeleccion> jugador : jugadores.entrySet()){
String clave = jugador.getKey();
JugadorSeleccion valor = jugador.getValue();
System.out.println(clave+"  ->  "+valor.toString());
}

Como resultado de esta ejecución del código tenemos el siguiente:

Busquets   ->  16  --  Busquets        --  Medio Centro
Capdevila  ->  11  --  Capdevila       --  Lateral Izquierdo
Casillas   ->  1   --  Casillas        --  Portero
Iniesta    ->  6   --  Iniesta         --  Interior Derecho
Pedrito    ->  18  --  Pedrito         --  Interior Izquierdo
Pique      ->  13  --  Pique           --  Central
Puyol      ->  5   --  Puyol           --  Central
Ramos      ->  15  --  Ramos           --  Lateral Derecho
Villa      ->  7   --  Villa           --  Delantero
Xabi       ->  14  --  Xabi Alonso     --  Medio Centro
Xavi       ->  8   --  Xavi Hernandez  --  Centro Campista

Si nos definimos nuestras propias clases y trabajamos con ellas en los Map, hay que tener muy claro una importante premisa en la programación “No es lo mismo ‘Iguales’ que ‘Lo mismo’ “. Esto quiere decir, que si nos creamos un nuevo objeto de la clase “JugadorSelección” cuyos atributos son Iguales que un objeto que se encuentre en el Map y ejecutamos el método “ContainsValue” nos devolverá un “false como una casa”. Porque aunque sean objetos iguales, no son los mismo objetos, y por tanto, no lo contendrá el Map. Es decir, que si hacemos lo siguiente nos devolverá un false, debido a que nuestro objeto ‘villla’ no será el mismo que está en el Map:

// Cuidado con comparar objetos que son iguales pero no son lo mismo
JugadorSeleccion villa = new JugadorSeleccion(7, "Villa", "Delantero");
System.out.println("Esta este objeto 'villa' en el Map: jugadores.containsValue(villa) = "+jugadores.containsValue(villa));

Como salida conseguiremos la siguiente:

Esta este objeto 'villa' en el Map: jugadores.containsValue(villa) = false
En cambio, si ejecutamos lo que viene a continuación, estaremos preguntando por un objeto que sí que está dentro del Map:

// En este caso si que estamos preguntando por el mismo objeto
JugadorSeleccion navas = new JugadorSeleccion(22, "Navas", "Extremo Derecho");
jugadores.put("Navas", navas);
System.out.println("Esta este objeto 'navas' en el Map: jugadores.containsValue(navas) = "+jugadores.containsValue(navas));

Y como salida mostrará lo que sigue:

Esta este objeto 'navas' en el Map: jugadores.containsValue(navas) = true
En lo relacionado con trabajar con objetos “propios” es lo único en lo que hay que tener cuidado. Aunque los que estéis acostumbrados a programar en lenguajes como C o C++ en los que hay que tener muchísimo cuidado con los punteros, ésto lo tendréis más que superado. Sobre el resto de métodos, a la hora de trabajar con objetos “propios”, no hay mucho más que decir.

Tambien les dejo unos videos explicativos, muy buenos sobre Maps en Java, explicando e implementando los maps.

Parte 1/3

Parte 2/3

Parte 3/3


Cualquier duda sobre los Map, no dudéis en preguntarla dejando un comentario en la entrada o en el Foro.