Jaki jest pożytek z dodawania pustego klucza lub wartości do HashMap w Javie?

91

HashMap zezwala na jeden klucz pusty i dowolną liczbę wartości null. Jaki jest pożytek z tego?

subhashis
źródło
11
„Być może problemem nie jest to, że nic nam nie przeszkadza, ale to, że przeszkadzamy”.
bmargulies
3
W kolekcjach Guava, Google, wiele klas nie dopuszcza wartości null, a powodem tego jest to, że 95% przypadków nie wymaga wartości null i mogą reprezentować błędy, potencjalnie trudne do znalezienia.
stivlo
Dziwne jest to, że ConcurrentHashMapnie obsługuje klawiszy zerowych, podczas gdy HashMaptak.
codepleb
2
Tylko HashMap dopuszcza null :)
subhashis

Odpowiedzi:

126

Nie jestem pewien, o co pytasz, ale jeśli szukasz przykładu, kiedy chciałoby się użyć klucza zerowego, często używam ich na mapach, aby przedstawić domyślny przypadek (tj. Wartość, która powinna być użyta jeśli nie ma podanego klucza):

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

HashMapobsługuje klucze o wartości null specjalnie (ponieważ nie może wywołać .hashCode()obiektu zerowego), ale wartości null nie są niczym specjalnym, są przechowywane na mapie jak wszystko inne

Michał Mrozek
źródło
4
Więc jeśli .hashCode () nie jest możliwe na null, kto decyduje, do którego karetki wejdzie pusty klucz?
Pacerier,
26
@Pacerier Jest specjalna metoda w HashMap( putForNullKey), która to obsługuje; przechowuje to w tabeli 0
Michał Mrozek
1
@MichaelMrozek twoja ostatnia linia B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);Myślę, że możemy po prostu wywołać metodę get na kluczu wyszukiwania, co da ten sam wynik. B val = foo.get(search);czy mógłbyś mnie poprawić, jeśli coś jest nie tak?
dheerajraaj
6
@ dheeraj92 Twój kod zostanie ustawiony valna, nulljeśli klucz nie istnieje; mój ustawia go na dowolne nullmapy na mapie. O to właśnie chodziło, zapisuję domyślną wartość niezerową pod nullkluczem w mapie i używam jej, jeśli rzeczywisty klucz nie istnieje
Michael Mrozek
28

Jednym z przykładów może być modelowanie drzew. Jeśli używasz HashMap do reprezentowania struktury drzewa, gdzie klucz jest elementem nadrzędnym, a wartością jest lista dzieci, wówczas wartościami nullklucza byłyby węzły główne.

Tony
źródło
6

Jednym z przykładów użycia null wartości jest użycie HashMapjako pamięci podręcznej wyników kosztownej operacji (takiej jak wywołanie zewnętrznej usługi sieciowej), która może powrócić null.

Umieszczenie nullwartości na mapie pozwala następnie na rozróżnienie między przypadkiem, w którym operacja nie została wykonana dla danego klucza ( cache.containsKey(someKey)zwraca false), a gdzie operacja została wykonana, ale zwróciła nullwartość ( cache.containsKey(someKey)zwraca true, cache.get(someKey)zwraca null).

Bez nullwartości należałoby albo umieścić w pamięci podręcznej jakąś specjalną wartość, aby wskazać nullodpowiedź, albo po prostu w ogóle nie buforować tej odpowiedzi i wykonywać operację za każdym razem.

Zorac
źródło
3

Dotychczasowe odpowiedzi uwzględniają tylko wartość posiadania nullklucza, ale pytanie dotyczy również any number of null values.

Korzyści płynące z przechowywania wartości nullw kluczu w HashMap są takie same jak w bazach danych itp. - można zapisać rozróżnienie między wartością, która jest pusta (np. Ciąg „”), a brakiem wartości w ogóle (null) .

Eborbob
źródło
2

Oto mój jedyny nieco wymyślony przykład przypadku, w którym nullklucz może być przydatny:

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
źródło
Jeśli próbujesz zatrzymać nieistniejący licznik czasu lub taki, który został już zatrzymany, powinien to być błąd, a nie zignorowany.
Załóż pozew Moniki
@QPaysTaxes - Zależy od Twojego zamiaru. Jeśli potrzebujesz lekkiego narzędzia, którego można łatwo używać, na ogół nie chcesz go mieć throw Exception. Poza tym to nie jest tak, że próba zatrzymania nieistniejącego lub już zatrzymanego timera jest czymś, z czego dzwoniący może ogólnie odzyskać.
aroth
1

Inny przykład: używam go do grupowania danych według daty. Ale niektóre dane nie mają daty. Mogę to zgrupować z nagłówkiem „NoDate”

Anthone
źródło
0

Klucz pusty może być również pomocny, gdy mapa przechowuje dane dla wyborów interfejsu użytkownika, w których klucz mapy reprezentuje pole fasoli.

Odpowiednia wartość pola zerowego byłaby na przykład reprezentowana jako „(proszę wybrać)” w wyborze interfejsu użytkownika.

Gunnar
źródło