Qual é a utilidade de adicionar uma chave ou valor nulo a um HashMap em Java?

91

HashMap permite uma chave nula e qualquer número de valores nulos. Qual é a utilidade disso?

subhashis
fonte
11
"Talvez o problema não seja que nada esteja nos incomodando, mas que estamos incomodando."
bmargulies
3
Em Guava, coleções do Google, muitas classes não permitem null e o raciocínio por trás disso é que 95% dos casos não precisam de null e podem representar bugs, potencialmente difíceis de encontrar.
stivlo
O estranho é que ConcurrentHashMapnão suporta chaves nulas, mas HashMapsim.
codepleb
2
Apenas o HashMap permite null :)
subhashis

Respostas:

126

Não tenho certeza do que você está perguntando, mas se você está procurando um exemplo de quando alguém gostaria de usar uma chave nula, eu as uso frequentemente em mapas para representar o caso padrão (ou seja, o valor que deve ser usado se uma determinada chave não estiver presente):

Map<A, B> foo;
A search;
B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);

HashMaplida com chaves nulas especialmente (uma vez que não pode chamar .hashCode()um objeto nulo), mas os valores nulos não são nada de especial, eles são armazenados no mapa como qualquer outra coisa

Michael Mrozek
fonte
4
Portanto, se .hashCode () não for possível em null, quem decide em qual carro a chave nula entrará?
Pacerier
26
@Pacerier Existe um método especial em HashMap( putForNullKey) que trata disso; ele o armazena na tabela 0
Michael Mrozek
1
@MichaelMrozek sua última linha B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);, acho que podemos simplesmente chamar o método get na chave de pesquisa que terá o mesmo resultado. B val = foo.get(search);você poderia me corrigir se eu estou entendendo algo errado?
dheerajraaj
6
@ dheeraj92 Seu código será definido valcomo nullse a chave não existir; o meu define para qualquer nullmapa no mapa. Esse era o ponto, eu armazenei um valor não nulo padrão na nullchave do mapa e o utilizo se a chave real não existir
Michael Mrozek
28

Um exemplo seria modelar árvores. Se você estiver usando um HashMap para representar uma estrutura de árvore, onde a chave é o pai e o valor é a lista de filhos, então os valores da nullchave seriam os nós raiz.

Tony
fonte
6

Um exemplo de uso de null valores é ao usar um HashMapcomo cache para resultados de uma operação cara (como uma chamada para um serviço da web externo) que pode retornar null.

Colocar um nullvalor no mapa permite distinguir entre o caso em que a operação não foi realizada para uma determinada chave ( cache.containsKey(someKey)retorna false) e onde a operação foi realizada, mas retornou um nullvalor ( cache.containsKey(someKey)retorna true, cache.get(someKey)retorna null).

Sem nullvalores, você teria que colocar algum valor especial no cache para indicar uma nullresposta ou simplesmente não armazenar em cache essa resposta e executar a operação todas as vezes.

Zorac
fonte
3

As respostas até agora consideram apenas o valor de ter uma nullchave, mas a pergunta também pergunta sobre any number of null values.

O benefício de armazenar o valor em nullrelação a uma chave em um HashMap é o mesmo que em bancos de dados, etc - você pode registrar uma distinção entre ter um valor que está vazio (por exemplo, string "") e não ter nenhum valor (nulo) .

Eborbob
fonte
2

Aqui está meu único exemplo um tanto artificial de um caso em que a nullchave pode ser útil:

public class Timer {
    private static final Logger LOG = Logger.getLogger(Timer.class);
    private static final Map<String, Long> START_TIMES = new HashMap<String, Long>();

    public static synchronized void start() {
        long now = System.currentTimeMillis();
        if (START_TIMES.containsKey(null)) {
            LOG.warn("Anonymous timer was started twice without being stopped; previous timer has run for " + (now - START_TIMES.get(null).longValue()) +"ms"); 
        }
        START_TIMES.put(null, now);
    }

    public static synchronized long stop() {
        if (! START_TIMES.containsKey(null)) {
            return 0;
        }

        return printTimer("Anonymous", START_TIMES.remove(null), System.currentTimeMillis());
    }

    public static synchronized void start(String name) {
        long now = System.currentTimeMillis();
        if (START_TIMES.containsKey(name)) {
            LOG.warn(name + " timer was started twice without being stopped; previous timer has run for " + (now - START_TIMES.get(name).longValue()) +"ms"); 
        }
        START_TIMES.put(name, now);
    }

    public static synchronized long stop(String name) {
        if (! START_TIMES.containsKey(name)) {
            return 0;
        }

        return printTimer(name, START_TIMES.remove(name), System.currentTimeMillis());
    }

    private static long printTimer(String name, long start, long end) {
        LOG.info(name + " timer ran for " + (end - start) + "ms");
        return end - start;
    }
}
aroth
fonte
Se você está tentando parar um cronômetro inexistente ou que já foi interrompido, isso deve ser um erro, não ignorado.
Processo judicial de Monica
@QPaysTaxes - Depende de sua intenção. Se você quer um utilitário leve que possa ser usado facilmente, geralmente não quer ficar por throw Exceptionperto. Além disso, tentar parar um cronômetro inexistente ou já parado é algo do qual o chamador geralmente pode se recuperar.
aroth
1

Outro exemplo: eu o utilizo para agrupar dados por data. Mas alguns dados não têm data. Posso agrupá-lo com o cabeçalho "NoDate"

Anthone
fonte
0

Uma chave nula também pode ser útil quando o mapa armazena dados para seleções de IU em que a chave do mapa representa um campo de bean.

Um valor de campo nulo correspondente seria, por exemplo, representado como "(selecione)" na seleção da IU.

Gunnar
fonte