2011-01-28 207 views
32

我在我的代码中有一个Map<String, List<String>>,如果映射的#get()方法返回一个空列表而不是null,那么我会避免潜在的空指针。在java API中有这样的事情吗?我应该只是延长HashMapJava Map实现返回一个默认值而不是null

+7

使用Decorator模式很可能比HashMap中延伸......好我 – kem 2011-01-28 21:50:56

+1

不怀疑你,但为什么会更好? – 2011-01-28 21:52:55

+7

@jk:你为什么要限制自己*总是*作为一个HashMap?如果有时你想要一个LinkedHashMap?还是一个ConcurrentHashMap?还是一个TreeMap?基本上,赞成组合比继承:) – 2011-01-28 21:54:05

回答

23

@ Jon的回答是一种很好的方式来做你直接要求的东西。

但是,让我感到你可能试图实现的是一个“multimap”;即从一个键到一组值的映射。如果是这种情况,那么你还应该看看Guava或Apache commons集合中的multimap类。

看:

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

在我看来,你可以简单地编写一个包装函数来获得你想要的值,如果它是null返回默认代替。

Map<String, List<String>> myMap = new Map<String, List<String>>(); 

public List<String> myGet(String key) { 
    List<String> ret = myMap.get(key); 
    if(ret == NULL) { 
     return defaultList(); // where defaultList is a function that generates your default list. 
    } 
    return ret; 
} 

这是假设你的myMap是一个全局变量(为简单起见),如果这不是你想要的那么你还可以扩展MapHashMap成类似MyMap,只是包括这个额外的功能。这样你就可以在任何一个MyMap对象被实例化的地方使用它。

8

与以前的帖子类似,除非您可以重写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; 
    } 
}; 
7

番石榴有一个方法来做你想要的。它与Argote's answer类似。

Map<String, List<String>> myMap = ... 
Functions.forMap(myMap, Arrays.asList("default", "value")); 
25

由于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" 
相关问题