Estas classes são muito populares. Isso porque elas têm grande utilidade para o desenvolvedor. Infelizmente elas também são horrivelmente ineficientes. Hashtable
e HashMap
embalam cada par chave/valor em um objeto Entry
. Uma instância de Entry
é surpreendentemente grande. Ela não somente segura uma referência para a chave e valor mas também armazena o hash e uma referência para o próximo Entry
do hash bucket*. Se você olhar o heap dump com um analisador de memória, ficará chocado com o quanto de espaço é gasto por eles em aplicações grandes. Se você olhar o código-fonte da classe HashSet
, você verá que os desenvolvedores foram extremamente preguiçosos e apenas usaram um HashMap
por trás dos panos!
Antes de usar qualquer uma dessas classes, pense novamente. IdentityHashMap
pode ser uma alternativa viável. Mas tenha cuidado: ele intencionalmente quebra a interface Map
. Ele é muito mais eficiente no uso da memória devido à implementação de uma hashtable
aberta (sem buckets), sem necessidade de um objeto Entry
e usa um simples Object[]
na retaguarda.
Em vez de um HashSet
, um simples ArrayList
pode funcionar similarmente bem (você pode usar o método contains(Object))
desde que ele seja pequeno e buscas sejam raras.
Para Sets
, use apenas um ArrayList
ou mesmo um array.
Realmente é uma vergonha que não existam implementações eficientes de Map
e Set
na Standard JDK!
*Nota do Tradutor: bucket é o local onde são armazenados os itens que possuem o mesmo hash (em caso de colisão).