返回默认值而不是null的Java Map实现

jk.*_*jk. 36 java default

Map<String, List<String>>我的代码中有一个,如果map的#get()方法返回一个空列表而不是null ,我会避免使用潜在的空指针.java API中有这样的东西吗?我应该延长HashMap吗?

Jef*_*rey 31

多亏了default方法,Java 8现在内置了Map::getOrDefault:

Map<Integer, String> map = ...
map.put(1, "1");
System.out.println(map.getOrDefault(1, "2")); // "1"
System.out.println(map.getOrDefault(2, "2")); // "2"
Run Code Online (Sandbox Code Playgroud)

  • 这是最微小的答案,因为它不需要番石榴.顺便说一句,这正是我所寻找的.Upvoting. (2认同)
  • 看起来基于时间,这是最好的解决方案,但来到派对的方式很晚(感谢java 8!).我喜欢它的简洁.+1 (2认同)

Ste*_*n C 25

@ Jon的回答是直接做你要求的好方法.

但令我感到震惊的是,您可能尝试实施的是"多图"; 即从键到值集合的映射.如果是这种情况,那么您还应该查看Guava或Apache commons集合中的multimap类.

看着:

  • +1和`get()`在一个不包含密钥的`Multimap`上按合同返回一个空的`Collection` ......正是OP想要的.具有未指定行为的Apache Commons`MultiMap`也是如此. (4认同)
  • @ColinD True.使用apache commons时,我们可以使用DefaultedMap,它在地图不包含指定值时返回默认值. (2认同)

Jon*_*eet 24

如评论中所述:

番石榴的计算地图概念被取代了LoadingCache.另外java 8介绍了Map接口不错的computeIfAbsent默认方法,它不会破坏地图合约并具有延迟评估功能.


Guava有一个"计算地图"的想法,如果它不存在,它将执行一个提供值的函数.它是在MapMaker.makeComputingMap; 您现在可以使用CacheBuilder- 请参阅CacheBuilder.build更多详细信息.

这可能是矫枉过正你以后-你可能会更好只写Map它的实现一个Map(使用成分而不是扩展任何特定的实现),然后就返回默认值,如果它不存在.除了get可能只委托给其他地图之外的每个方法:

public class DefaultingMap<K, V> implements Map<K, V>
{
    private final Map<K, V> map;
    private final V defaultValue;

    public DefaultingMap(Map<K, V> map, V defaultValue)
    {
        this.map = map;
        this.defaultValue = defaultValue;
    }

    @Override public V get(Object key)
    {
        V ret = map.get(key);
        if (ret == null)
        {
            ret = defaultValue;
        }
        return ret;
    }

    @Override public int size()
    {
        return map.size();
    }

    // etc
}
Run Code Online (Sandbox Code Playgroud)

  • 注意:只做这会打破`get()`的契约:如果地图不包含键,则返回`null`.为了符合要求,你应该将`containsKey()`重写为*always*return`true`.我会假设`makeComputingMap()`也会这样做,但没有在文档中明确说明. (4认同)
  • @Mark:可能.虽然然后你会在迭代密钥时陷入困境,但基本上迟早抽象会中断.*哪里*你打破它肯定是一个深思熟虑的问题:) (3认同)
  • 或者,您可以扩展com.google.common.collect.ForwardingMap(来自Google Guava),这使得实现@JonSkeet的建议更加简洁. (3认同)
  • `// etc` 并不小,这使得这个解决方案在 IMO 中不切实际。 (2认同)
  • Guava的计算地图概念已被[LoadingCache](https://code.google.com/p/guava-libraries/wiki/CachesExplained)取代.另外java 8介绍了Map接口不错[computeIfAbsent](http://stackoverflow.com/a/31234010/603516)默认方法,它不会破坏地图合约和懒惰评估功能 (2认同)

Pet*_*rey 10

与之前的帖子类似,但如果要更改其行为,则可以覆盖get方法.

Map<String, List<String>> map = new LinkedHashMap<String, List<String>>() {
    public String get(Object key) {
        List<String> list = super.get(key);
        if (list == null && key instanceof String)
           super.put(key, list = new ArrayList<String>());
        return list;
    }
}; 
Run Code Online (Sandbox Code Playgroud)


Hea*_*ers 7

番石榴有一种方法可以完全按照你的意愿去做.它类似于Argote的答案.

Map<String, List<String>> myMap = ...
Functions.forMap(myMap, Arrays.asList("default", "value"));
Run Code Online (Sandbox Code Playgroud)

  • 也许我错过了什么,但是如何创建一个具有默认值的`Map`实现呢? (2认同)
  • OP想要打破`Map`的合同,所以OP想要的东西不是`Map`.:) (2认同)