entre diferencia cual java hashmap hashtable

java - diferencia - hashmap vs hashset



¿Por qué Hashtable no permite claves o valores nulos? (6)

Hashtable es la clase más antigua, y su uso es generalmente desaconsejado. Quizás vieron la necesidad de una clave nula y, lo que es más importante, de valores nulos, y la agregaron en la implementación de HashMap.

HashMap es más nuevo y tiene capacidades más avanzadas, que son básicamente una mejora de la funcionalidad Hashtable. Cuando se creó HashMap, se diseñó específicamente para manejar valores nulos como claves y manejarlos como un caso especial.

Editar

De Hashtable JavaDoc :

Para almacenar y recuperar con éxito objetos de un Hashtable, los objetos utilizados como claves deben implementar el método hashCode y el método equals.

Como null no es un objeto, no puede llamar a .equals() o .hashCode() , por lo que Hashtable no puede calcular un hash para usarlo como clave.

Como se especifica en la documentación de JDK, Hashtable no permite claves o valores nulos. HashMap permite una clave nula y cualquier número de valores nulos. ¿Por qué es esto?


La razón es la razón en la respuesta aceptada: Hashtable es viejo.

Sin embargo, el uso de Hashtable NO se desaconseja a favor de HashMap en todos los escenarios.

  • Hashtable está sincronizado, por lo que es THREAD-SAFE . HashMap no lo es.

Ni Hashtable ni ConcurrentHashMap admiten claves o valores nulos. HashMap lo hace.

Si desea un reemplazo directo que no requiere nada más que cambiar la clase y funciona en todos los escenarios, no hay ninguno. La opción más similar sería ConcurrentHashMap (que es seguro para subprocesos pero no admite el bloqueo de toda la tabla):

Esta clase es totalmente interoperable con Hashtable en programas que se basan en la seguridad de sus subprocesos pero no en sus detalles de sincronización.

HashMap es un mejor reemplazo para las aplicaciones de un solo hilo o en cualquier momento en que la sincronización no sea un requisito, debido a la introducción del impacto en la sincronización.

Fuentes:


La razón principal por la que Hashtable y Concurrent HashMap no permiten claves o valores nulos es la expectativa de que se utilizarán en un entorno de subprocesos múltiples. Por un minuto, supongamos que se permiten valores nulos. En este caso el método get tiene un comportamiento ambiguo. Puede devolver nulo si la clave no se encuentra en el mapa o puede devolver nulo si se encuentra la clave y su valor es nulo. Cuando un código espera valores nulos, generalmente verifica si la clave está presente en el mapa para que pueda saber si la clave no está presente o si la clave está presente pero el valor es nulo. Ahora este código se rompe en un entorno de subprocesos múltiples. Echemos un vistazo al siguiente código:

if (map.contains(key)) { return map.get(key); } else { throw new KeyNotFoundException; }

En el código anterior, digamos que el hilo t1 llama al método contiene y encuentra la clave y asume que la clave está presente y está lista para devolver el valor, ya sea nulo o no. Ahora, antes de que llame a map.get, otro hilo t2 elimina esa clave del mapa. Ahora t1 se reanuda y devuelve nulo. Sin embargo, según el código, la respuesta correcta para t1 es KeyNotFoundException porque la clave se ha eliminado. Pero aún así devuelve el nulo y por lo tanto el comportamiento esperado se rompe.

Ahora, para un HashMap normal, se supone que un solo hilo lo llamará, por lo tanto, no hay posibilidad de que la clave se elimine en medio de "contiene" verificación y "obtener". Así que HashMap puede tolerar valores nulos. Sin embargo, para Hashtable y ConcurrentHashMap, las expectativas son claras de que múltiples subprocesos actuarán sobre los datos. Por lo tanto, no pueden permitirse el lujo de permitir valores nulos y dar una respuesta incorrecta. La misma lógica se aplica a las claves. Ahora el argumento del contador puede ser: los pasos que contienen y obtienen pueden fallar para valores no nulos para Hashtables y ConcurrentHashMaps, porque otro hilo puede modificar el mapa / tabla antes de que se ejecute el segundo paso. Eso es correcto, puede suceder. Pero como Hashtables y ConcurrentHashMaps no permiten claves y valores nulos, no es necesario que los implementos contengan y verifiquen en primer lugar. Pueden obtener el valor directamente porque saben que si el método get devuelve un valor nulo, la única razón es que la clave no está presente y no porque el valor podría ser nulo. El contenido y la verificación de obtención son necesarios solo para HashMaps porque permiten los valores nulos y, por lo tanto, necesitan resolver la ambigüedad sobre si no se encuentra la clave o si el valor es nulo.


La tabla de hash es una clase muy antigua, desde JDK 1.0

Para entender esto, primero debemos entender los comentarios escritos en esta clase por el autor. “Esta clase implementa una tabla hash, que asigna claves a valores. Cualquier objeto que no sea nulo se puede usar como clave o como valor. "Para almacenar y recuperar con éxito objetos de una tabla hash, los objetos utilizados como claves deben implementar el método hashCode y el método equals".

La clase HashTable se implementa en el mecanismo de hash, que significa almacenar cualquier par clave-valor, su código hash requerido del objeto clave. Si la clave es nula, no podrá realizar el hash, lo hará a través de la excepción de puntero nulo y un caso similar para el valor que está lanzando nulo si el valor es nulo.

Pero más tarde, se dio cuenta de que la clave nula y el valor tienen su propia importancia, por eso se permite una clave nula y múltiples valores nulos en clases implementadas posteriormente como la clase HashMap.

Para el hash map, las claves nulas permitirán y hay una comprobación nula para las claves si la clave es nula, entonces ese elemento se almacenará en una ubicación cero en la matriz de entrada. Clave nula que podemos usar para algún valor por defecto ..

=> Los métodos Hashtable están sincronizados, nunca utiliza el bloqueo basado en objetos.

HashMap implementa considerándolo especial

static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

Java 8 no puedes inferir tipos para la tabla hash.

private Map<String,String> hashtable = new Hashtable<>(); // Not Allowed private Map<String,String> hashtable = new HashMap<>(); // Allowed


así que para concluir

Porque en HashTable, cuando pones un elemento, tendrá en cuenta el hash de clave y valor. Básicamente tendrás algo como:

public Object put(Object key, Object value){ key.hashCode(); //some code value.hashCode(); }

HashTable: no permite claves nulas Esto se debe a que, en el método put (clave K, valor V), tenemos key.hashcode () que genera una excepción de puntero nulo. HashTable: no permite el valor nulo Esto se debe a que, en el método put (clave K, valor V), tenemos si (valor == nulo) {lanzar una nueva excepción NullPointerException

HashMap permite valores nulos ya que no tiene ninguna comprobación como HashTable, mientras que solo permite una clave nula. Esto se hace con la ayuda del método putForNullKey, que agrega el valor al índice 0 de la matriz interna cada vez que se proporciona la clave como nula


HashTable - No permite claves nulas
Esto se debe a que, en el método put (clave K, valor V), tenemos key.hashcode() que lanza una excepción de puntero nulo.
HashTable - No permite valor nulo
Esto se debe a que en el método put (clave K, valor V) tenemos if(value==null){throw new NullPointerException

HashMap permite valores nulos ya que no tiene ninguna comprobación como HashTable, mientras que solo permite una clave nula. Esto se hace con la ayuda del método putForNullKey, que agrega el valor al índice 0 de la matriz interna cada vez que se proporciona la clave como nula