En esta ocasión voy a compartir un ejemplo en el que se ve como utilizar tablas hash en Java mediante la clase HashMap.
Imaginemos que necesitamos una aplicación para una tienda mediante la que queremos almacenar los distintos productos que venderemos y el precio que tendrán. Y se quiere que tenga las funciones básicas, introducir un elemento, modificar su precio, eliminar un producto y mostrar los productos que tenemos con su precio.
Vamos con la resolución del ejemplo de HashMap en Java. En primer lugar para hacerlo sencillo hacemos una aplicación para consola y con unos pocos System.out.println y la clase Scanner para leer desde teclado se crea un sencillo menú con las posibles opciones y con un switch se llama a las distintas funciones para tratar el HashMap.
public static void main(String[] args) {
HashMap<String,Float> listaProductos = new HashMap<String,Float>();
Scanner sc = new Scanner(System.in);
int opcionElegida = 0;
float precio;
String codigo;
while (opcionElegida != 5) {
System.out.println("Introduce el numero de la opción que quieras:");
System.out.println("1.- Introducir producto");
System.out.println("2.- Modificar precio");
System.out.println("3.- Mostrar todos los productos");
System.out.println("4.- Eliminar producto");
System.out.println("5.- Salir");
opcionElegida = sc.nextInt();
switch (opcionElegida) {
case 1:
System.out.println("Introduce el códido del producto:");
codigo = sc.next();
System.out.println("Introduce el precio del producto:");
precio = sc.nextFloat();
guardarProducto(codigo, precio, listaProductos);
break;
case 2:
System.out.println("Introduce el códido del producto del que quieres cambiar el precio:");
codigo = sc.next();
modificaPrecio(codigo, listaProductos);
break;
case 3:
mostrarProductos(listaProductos);
break;
case 4:
System.out.println("Introduce el códido del producto que quieres eliminar:");
codigo = sc.next();
eliminaProducto(codigo, listaProductos);
break;
case 5:
break; // Si la opcion es 5 no se hace nada
default:
System.out.println("Tienes que introducir una opción valida");
}
}
}
Usamos métodos estáticos para no tener que instanciar ningún objeto y ahorrarnos llamar a las funciones desde un objeto porque para lo sencillo que es el ejemplo no tiene sentido crear por ejemplo una clase tienda y ponerle esos métodos o por lo menos es tan innecesario como que las operaciones de la clase Math tampoco fuesen estáticas.
Empezamos con la función que guarda un nuevo producto, es decir, que añade un nuevo elemento al HashMap. Primero comprobamos que no halla ningún elemento con el código introducido y si es así añadimos el elemento con la función HashMap.put(clave,contenido).
public static void guardarProducto(String codigo, float precio, HashMap <String,Float> listaProductos){
if (listaProductos.containsKey(codigo)) {
System.out.println("No se puede introducir el producto. El código esta repetido.");
} else {
listaProductos.put(codigo, precio);
}
}
La función para modificar un elemento es prácticamente igual que la anterior pero, la función HashMap.put(clave,contenido) en esta ocasión se ejecutara cuando se encuentre algún elemento con la clave pasada. Como se puede ver la función put(clave,valor) añade un nuevo elemento si la clave no esta repetida y modifica el elemento con la clave pasada si ya había un elemento con esa clave.
public static void modificaPrecio(String codigo, HashMap<String,Float> listaProductos){
Scanner sc = new Scanner(System.in);
if (listaProductos.containsKey(codigo)) {
System.out.println("Introduce el precio del producto:");
listaProductos.put(codigo, sc.nextFloat());
} else {
System.out.println("No hay ningun producto con ese código.");
}
}
La función encargada de mostrar los productos es la que tiene quizás un poco más de dificultad a priori porque para recorrer una hashMap no hay índices como en los arrays o ArrayList y es necesario usar un iterador para recorrer el Hashmap.
Vamos a ver las 2 formas de recorrer un Hashmap en Java, usando entrySet() o usando keySet().
Con keySet() lo que se obtiene como indica el nombre de la función son las claves y mediante un iterador se recorre la lista de claves. De esta forma si queremos saber también el valor de cada elemento tenemos que usar la función get(clave).
public static void mostrarProductos(HashMap<String, Float> listaProductos) {
String clave;
Iterator<String> productos = listaProductos.keySet().iterator();
System.out.println("Hay los siguientes productos:");
while(productos.hasNext()){
clave = productos.next();
System.out.println(clave + " - " + listaProductos.get(clave));
}
}
La otra opción es entrySet() con la que se obtienen los elementos enteros y al igual que en el caso anterior con un iterador se recorre el hashMap, pero de esta forma hay que crear una variable de tipo Map.Entry para almacenar el elemento y con los métodos getKey() y getValue() de Map.Entry se obtienen los valores. Nota: Se puede usar un iterador del tipo que vamos a cojer en este caso Map.Entry
public static void mostrarProductos2(HashMap<String, Float> listaProductos) {
Iterator iterador = listaProductos.entrySet().iterator();
//Iterator<Map.Entry<String, Float>> iterador = listaProductos.entrySet().iterator();
Map.Entry producto;
while (iterador.hasNext()) {
producto = (Map.Entry) iterador.next();
//producto = iterador.next(); Si se usase tambien la otra linea comentada.
System.out.println(producto.getKey() + " - " + producto.getValue());
}
}
Con esta segunda forma es necesario usar una variable Map.Entry y realizar el import pertinente, pero el resultado es el mismo y el numero de líneas de código es igual, aunque esta segunda forma supongo que sea más eficiente puesto que mientras que en la primera solo obtenemos la clave y luego hay que buscar el contenido asociado con la función get(clave) con esta segunda forma ya tenemos ambos valores y no hay que realizar esa búsqueda adicional, aunque quizás la primera forma sea mas «sencilla».
Y finalmente la función para eliminar un producto, en la que primero comprobamos que exista un elemento con la clave pasada y si es así se elimina con la función remove(clave).
public static void eliminaProducto(String codigo, HashMap<String,Float> listaProductos) {
if (listaProductos.containsKey(codigo)) {
listaProductos.remove(codigo);
} else {
System.out.println("No hay ningun producto con ese código.");
}
}
Muchas gracias por este código, se entiende MUY bien 😉 me salvaste la vida pues mañana tengo examen y me pidieron investigar sobre los hash map
Graxxx Men por el post: Excelente Explicación.
Me alegro de que te fuese util.
Muy bueno!
Buen post! justo estoy investigando cómo usar HashMap y aquí está muy bien explicado.
Aún así tengo una duda: por qué no usas .hashCode() y .equals()? Usar esta colección no te obliga a sobreescribir esos dos métodos? O no se requieren en tu código? jajaja estoy un poco perdida aún en esto XD
Si que estas un poco perdida XD no se puede hablar de sobreesbir métodos sin herencia porque sino no hay nada que sobreescribir y como no estoy heredando de HashMap (no tengo extends HashMap en mi clase).
En cualquier caso solo estas obligada a implementar (y no sobreescribir) cuando implementas una clase abstracta o una interfaz como por ejemplo Map (implements Map).
En cualquiere caso creo que no hay nada que te obligue a sobreescribir hashCode() y equals() en ninguna clase de Java porque ya tienen una implementación por defecto para Object y por lo tanto para cualquier clase, otra cosa es que pueda ser recomendable o util hacerlo y lo mismo para toString().
Mmm… de acuerdo. Aunque en otros sitios, y en clase de programación también, hablan de «sobreescribir hashCode() y equals()»…
La cosa es que TreeSet es mi colección favorita y estoy muy cómoda usándola; sobreescribo equals() o compareTo() cuándo y cómo lo necesito y a correr (el equals() es verdad que es opcional, al igual que el toString(), etc.). Pensaba que HashMap funcionaría más o menos del mismo modo, pero ahora que lo pienso TreeSet hereda de la interfaz Collection y HashMap de la interfaz Map. Puede que por eso no sean tan iguales.
Ah, y ves, aquí sí que hablamos de herencia. Creo que por eso lo del «sobreescribir» de antes. Creo que no me expliqué bien. Esos métodos ya están implementados por defecto, como tú dices, pero si decides que la implementación por defecto no te gusta y quieres cambiarla, modificas una implementación ya existente, es decir, que sobreescribes el método. No sé si esto es correcto pero así es como yo lo había entendido 😉
Siento haberme expedido tanto. Seguiré investigando a ver si gano mi batalla al HashMap. Este post, de verdad, me está ayudando mucho. Gracias por tu ayuda. 🙂
Creo que no me explique bien, si estuvieses usando los métodos hashCode() y equals() en el ejemplo de este post estarías sobreescribiendo los métodos de la clase Producto o como la quisieses llamar que no tiene nada que ver con la clase HashMap y por tanto son cosas independientes. Si listaProductos estuviese declarado de una clase que heredase de HashMap (y no de HashMap directamente) sería ahi donde tendrías que sobreescribirlo porque como te decia si los pusieses directamente en el ejemplo no estariás sobreescribiendo los métodos de HashMap.
Y si estas acostumbrada a sobreescribir esos métodos puedes hacer lo mismo con HashMap o con cualquier clase porque cualquier clase tiene esos métodos.
Y me alegro de que te sirva de ayuda.
Muy buen post!
No entiendo un pedo todavia,pero ya le voy agarrar la mano, muchas gracias 😛
buen tutorial, gracias
MIL GRACIASSSSSSSSSSSS
Hiciste que tuviera una epifania *-*
Clarisimo. Gracias!
Hola, ya se que tema viejo pero como es el tema de la indizaciòn, en este caso usas el còdigo del producto que te viene por parámetro. En caso de que yo maneje la indización, por ejemplo de palabras para un diccionario, mi clave deberìa ser numèrica y yo deberia ir incrementandola por mi cuenta en la clase cada vez que agrego un elemento al hashmap? muchas gracias!
Si lo que necesitas es almacenar palabras con un orden numerico puedes usar por ejemplo un arrayList y asi no tienes que manejar los indices y te será mucho mas sencillo sobretodo cuando tengas que insertar elementos en posiciones intermedias o eliminar algun elemento de la lista porque con un arraylist son muy sencillas ambas tareas y con un hashmap deberias ir modificando todos los indices de los elementos siguientes de la lista y para el caso de las inserciones hasta tendrías que crear una variable auxiliar porque al insertar en un hashmap un elemento con una clave que ya esta en uso lo que se hace es remplazar su contenido.
Y cómo se hace para extraer la clave de un HashMap ?
Por ejemplo, si tengo:
HashMap comida = new HashMap();
comida.put(«Queso», 2);
comida.put(«Jamón», 1);
y quiero que String segundaComida sea «Jamón», ¿cómo lo hago?