HashMap vs Hashtable em Java: diferenças e funcionamento interno

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

HashMap vs Hashtable em Java: quem vence? Entendendo por baixo dos panos

\n\n

Se você já se perguntou: "Qual é, afinal, a diferença entre HashMap e Hashtable?" — você não está sozinho. Esta é uma das perguntas mais populares no Stack Overflow, e não é à toa. Ambas as classes armazenam dados no formato "chave — valor", ambas usam hashing, mas vivem em mundos diferentes. Uma é rápida e moderna, a outra é antiga, confiável, mas um pouco lenta. Vamos dar uma olhada "por baixo dos panos" e entender o que é o quê.

\n\n

Neste artigo, não vamos apenas listar as diferenças. Vamos entender como funciona a mecânica interna, por que uma classe permite null e a outra não, e quando usar ConcurrentHashMap em vez de ambas.

\n\n

Uma breve viagem pela história

\n\n

Hashtable surgiu no Java ainda na versão 1.0. Foi uma das primeiras classes de coleção e, desde o início, era sincronizada. Naquela época, a multitarefa era rara, mas os desenvolvedores do Java decidiram se precaver. Mais tarde, no Java 2 (1.2), surgiram novas coleções do framework Collections Framework, e entre elas estava o HashMap. Ele não era sincronizado, mas era muito mais rápido. Desde então, o Hashtable é considerado legado (legacy), embora ninguém o tenha removido da linguagem.

\n\n

A principal diferença: sincronização e threads

\n\n

A primeira e mais importante diferença é a sincronização. Os métodos do Hashtable (por exemplo, put(), get(), remove()) são marcados com a palavra-chave synchronized. Isso significa que duas threads não podem executar o mesmo método simultaneamente no mesmo objeto Hashtable. Parece uma vantagem, mas na prática isso se torna um gargalo.

\n\n
// Hashtable — todos os métodos são sincronizados\nHashtable<String, String> table = new Hashtable<>();\ntable.put("key1", "value1"); // thread-safe, mas lento em alta concorrência\n\n// HashMap — não é sincronizado\nHashMap<String, String> map = new HashMap<>();\nmap.put("key1", "value1"); // rápido, mas não thread-safe\n
\n\n

Se você trabalha em uma aplicação single-thread (a maioria dos casos), o HashMap será mais rápido, pois não precisa gastar tempo adquirindo e liberando bloqueios. Se você precisar de segurança em threads, é melhor não usar Hashtable, mas sim ConcurrentHashMap (introduzido no Java 5). Ele usa um bloqueio mais refinado (segmentos ou bloqueios no nível de buckets) e funciona muito mais rápido em ambientes multi-thread.

\n\n

Null, null e mais null

\n\n

A segunda diferença importante é o tratamento de null. O HashMap permite usar null tanto como chave (apenas uma vez) quanto como valor (quantas vezes quiser). O Hashtable, por outro lado, lançará uma NullPointerException se você tentar passar null.

\n\n
HashMap<String, String> map = new HashMap<>();\nmap.put(null, "nullKey"); // OK\nmap.put("key", null);     // OK\nSystem.out.println(map.get(null)); // "nullKey"\n\nHashtable<String, String> table = new Hashtable<>();\n// table.put(null, "value"); // NullPointerException!\n// table.put("key", null);   // NullPointerException!\n
\n\n

Por que isso acontece? Tudo se resume a como o hashing funciona. No HashMap, para a chave null, é usado um código hash especial 0, e ela é colocada no bucket zero. O Hashtable, por sua vez, usa um mecanismo antigo, onde chamar hashCode() em null resulta em erro. Além disso, o Hashtable não foi projetado para valores null, pois isso quebraria a lógica das operações sincronizadas.

\n\n

Funcionamento interno: como a tabela hash funciona por baixo dos panos

\n\n

Para entender a diferença mais a fundo, vamos dar uma olhada interna. Tanto o HashMap quanto o Hashtable são baseados em uma tabela hash. Trata-se de um array de "buckets", onde cada bucket é uma lista encadeada (ou uma árvore, a partir do Java 8). Quando você adiciona

Blogs

Book Recommendations