Antes de conocer HashSet, nos introducimos primero “Java collections Frameworks” a quien definitmos como un conjunto de interfaces y clases en los paquetes, Java.util y java.util.concurrent, quien nos provee varios modelos de como organizar esos objetos u varias implementaciones, Esos modelos son llamados tipos de datos abstractos, Por ejemplo, que necesites organizar tu programa en una lista de objetos en lista secuencial porque su orden es importante y hay duplicidad de elementos [1],
Algunos términos importantes:
Collection: una secuencia de elementos individuales en las que se aplican una o mas reglas, Una lista(List) debe contener los elementos de la misma forma en que fueron insertados, un Set no puede tener elementos duplicados, un Queue produce los elementos en orden determinado por una Queue discipline (FIFO, LIFO) [2]
Map: un grupo de objetos pares clave-valor que apuntan un valor usando una llave. Un ArrayList apunta a un objeto usando un numero, en cierto sentido se asocia números a objetos, un Map apunta a un objeto usando otro objeto, eso se llama array asociativos, porque son objetos asociados a otros o un diccionario, porque apuntan a un objeto valor usando un objeto clave, algo similar como cuando buscas una definición usando una palabra en un diccionario físico [2].
Es necesario conocer estructura de datos como listas, arreglos, arboles, etc. y varios lenguajes ya implementan esto en API, y java no es la excepción, aquí muestro algunos con ventajas, implementación en código y que casos aplicar, en esta ocasión veremos la interfaz Set y sus implementaciones: HashSet, LinkedHashSet, TreeSet
1. ¿Qué es la interface Set?
Es una colección y parte de la Api Collection de Java, sin duplicidad donde el orden no es relevante
2. ¿Qué es HashSet?
Clase que implementa la interfaz Set, no almacena elementos duplicados (único) y almacena solo objetos utilizando tabla Hash (internamente se guarda como HashMap, donde la clave será el mismo objeto y el valor es un objeto constante, ver Fig. 1 ), no garantiza el orden de iteración del conjunto, permite null [3].
3. ¿Cuándo usar HashSet?
Si queremos ingresar un listado de elementos que sean individuales y únicos, no importa el orden, buscamos rapidez en búsqueda de elemento.
Para optimizar la búsqueda podemos definir el método HashCode usando un criterio en el método equals. Las definiciones de equals y hashCode deben ser compatibles, Si x.equals(y) es verdadero, entonces x.hashCode() debe ser el mismo valor que y.hashCode(). [5]
Un ejemplo practico, si queremos crear una colección HashSet de objetos de la clase Libro, que tiene 2 atributos identificación y nombre
Según la imagen se almacena 3 objetos en HashSet y luego uno mas con el mismo código y nombre.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
import java.util.*; class Libro{ public Libro(int codigo, String nombre){ this.codigo=codigo; this.nombre=nombre; } int codigo; String nombre; public int getCodigo(){ return this.codigo; } public void setCodigo(int codigo){ this.codigo=codigo; } public void setNombre(String nombre){ this.nombre=nombre; } public String getNombre(){ return this.nombre; } public String toString(){ return String.valueOf(codigo)+"-"+nombre; } } public class Main { public static void main(String[] args) throws Exception { Libro libro1 = new Libro(314123,"Biblia"); Libro libro2 = new Libro(312412,"La Iliada"); Libro libro3 = new Libro(3124412,"La divina Comedia"); Set hashSet = new HashSet(); hashSet.add(libro1); hashSet.add(libro2); hashSet.add(libro3); Libro libro4 = new Libro(314123,"Biblia"); hashSet.add(libro4); System.out.println(hashSet); } } |
Aquí por si quieres compilar online el código: https://paiza.io/projects/IEu6uwg7Fdbew5zueWED5g, en la siguiente imagen se muestra cómo trabaja internamente hashSet
El problema viene cuando el ultimo registro ingresado es idéntico a los demás, no cumpliendo con el criterio de elemento único, por lo que debemos modificar las funciones hashCode y equals de la siguiente forma:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
import java.util.*; class Libro{ public Libro(int codigo, String nombre){ this.codigo=codigo; this.nombre=nombre; } int codigo; String nombre; public int getCodigo(){ return this.codigo; } public void setCodigo(int codigo){ this.codigo=codigo; } public void setNombre(String nombre){ this.nombre=nombre; } public String getNombre(){ return this.nombre; } public String toString(){ return String.valueOf(codigo)+"-"+nombre; } @Override public boolean equals(Object object) { Libro libro = (Libro) object; if(libro.getCodigo() == this.codigo && libro.getNombre().equals(this.nombre)){ return true; } else{ return false; } } @Override public int hashCode() { int value; value = this.codigo + nombre.hashCode(); return value; } } public class Main { public static void main(String[] args) throws Exception { Libro libro1 = new Libro(314123,"Biblia"); Libro libro2 = new Libro(312412,"La Iliada"); Libro libro3 = new Libro(3124412,"La divina Comedia"); Set hashSet = new HashSet(); hashSet.add(libro1); hashSet.add(libro2); hashSet.add(libro3); Libro libro4 = new Libro(314123,"Biblia"); hashSet.add(libro4); System.out.println(hashSet); } } |
Aquí por si quieres compilar online el código: https://paiza.io/projects/4TScyIl7an53FkkeQJVVcg?language=java
De esta manera se redefinen los métodos equals() para que los objetos sean comparados por sus valores y no por posición de memoria, así mismo personalizamos el método hashCode() para que no se calcule en función a la ubicación de memoria (así lo hace hashCode() por defecto)
4. Análisis de Complejidad
Los valores de hashSet son usados para calcular el valor hashCode. El valor hashCode es usado para acceder al objeto, En el peor de los caso, este valor puede duplicarse por lo que la complejidad seria de O (n) [4]
5. Fuentes
1. Java Generics and Collections, M. Naftaling y P. Wadler
2. On Java 8, Bruce Eckel, 2021 MindView3. Web
3. Web https://docs.oracle.com/javase/9/docs/api/java/util/HashSet.html
4. Web https://www.educba.com/hashset-vs-hashmap/
5. Core Java: Volume I Fundamentals, 11th Edition
6. https://www.learnerslesson.com/JAVA/Java-equals()-&-hashCode()-with-HashSet.htm