在Java中向HashMap添加空键或值的用途是什么?


91

HashMap允许一个null键和任意数量的null值。有什么用?


11
“也许问题不在于没有什么困扰我们,而是我们正在困扰它。”
bmargulies 2010年

3
在Guava(谷歌集合)中,许多类不允许null,其背后的原因是95%的情况不需要null,它们可以表示错误,可能很难找到。
stivlo 2011年

奇怪的是,ConcurrentHashMap虽然不支持空键HashMap
codepleb

2
只有HashMap允许null :)
subhashis

Answers:


126

我不是很肯定您的要求,但是如果您正在寻找一个示例,该示例何时需要使用空键,我经常在映射中使用它们来表示默认情况(即应使用的值)如果不存在给定的密钥):

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

HashMap专门处理null键(因为它不能调用.hashCode()null对象),但是null值不是什么特别的东西,它们像其他任何东西一样存储在地图中


4
因此,如果.hashCode()不能用于null,谁决定null键将输入哪个回车?
Pacerier

26
@Pacerier HashMapputForNullKey)中有一个特殊的方法可以处理它;它将其存储在表0中
Michael Mrozek

1
@MichaelMrozek您的最后一行,B val = foo.containsKey(search) ? foo.get(search) : foo.get(null);我想我们可以简单地在搜索键上调用get方法,它将获得相同的结果。 B val = foo.get(search);如果我出了点问题,您能纠正我吗?
dheerajraaj

6
@ dheeraj92 如果密钥不存在,您的代码将设置valnull; 我将其设置为null地图中要映射的任何地图。就是这一点,我将默认的非null值存储null在映射中的键上,如果实际键不存在,请使用它
Michael Mrozek

28

一个例子是树的建模。如果使用HashMap表示树结构,其中键是父级,值是子级列​​表,则null键的值将是根节点。


6

null 用法的一个示例是当使用HashMap用作可能返回的昂贵操作(例如对外部Web服务的调用)的结果的缓存时null

把一个null在地图值,则可以让您在操作尚未对给定键(执行情况区分cache.containsKey(someKey)收益false),并在该操作已经执行,但返回的null值(cache.containsKey(someKey)回报truecache.get(someKey)回报率null)。

没有null值,您将不得不在缓存中放入一些特殊值以指示null响应,或者根本不缓存该响应并每次执行该操作。


3

到目前为止的答案仅考虑拥有一把null钥匙的价值,但问题还询问any number of null values

null针对HashMap中的键存储值的好处与在数据库中存储密钥的好处相同-您可以记录以下区别:具有空值(例如字符串“”)和完全不具有值(空) 。


2

这是null密钥可能有用的情况下我唯一做的例子:

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;
    }
}

如果您要停止一个不存在的计时器,或者已经停止的计时器,那应该是一个错误,不能忽略。
基金莫妮卡的诉讼

@QPaysTaxes-取决于您的意图。如果你想要一个轻量级的实用工具,可以很容易地使用,你通常希望throw Exception的周围。此外,呼叫者通常可以从中恢复尝试停止不存在或已停止的计时器。
aroth 2015年

1

另一个示例:我用它按日期对数据进行分组。但是有些数据没有日期。我可以将其与标题“ NoDate”分组


0

当映射存储用于UI选择的数据(映射键表示bean字段)时,空键也很有用。

相应的空字段值例如将在UI选择中表示为“(请选择)”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.