我厌倦了下面的模式:
value = map.get(key);
if (value == null) {
value = new Object();
map.put(key, value);
}
这个例子只涉及到当您使用嵌套映射来表示多维结构时要编写的额外代码的表面。
我确信在某个地方存在一些东西来避免这种情况,但是我的谷歌搜索没有得到任何相关的结果。有什么建议吗?
java.util.concurrent.ConcurrentMap
和from Java 8
Java.util.Map
putIfAbsent(K key, V value)
返回现有值,如果该值为空,则插入给定值。因此,如果key不存在值,则返回null并插入给定值,否则返回存在值
如果需要对值进行延迟求值,可以使用
computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
Java 8为Map添加了很好的方法:compute, computeIfPresent, computeIfAbsent
实现你需要的:
Object existingOrCreated = map.computeIfAbsent(key, (k) -> new Object());
这种模式的问题是,您必须以某种方式定义在get()
返回null时应该使用的值。
当然有一些图书馆和IIRC也有一些较新的集合这样做,但不幸的是我不记得是哪些了。
但是,您可以自己编写一个实用程序方法,只要您有一个创建新值的标准方法。像这样的代码可能会起作用:public static <K, V> V safeGet(K key, Map<K,V> map, Class<V> valueClass) throws /*add exceptions*/ {
V value = map.get(key);
if( value == null ) {
value = valueClass.newInstance();
map.put( key, value );
}
return value;
}
请注意,您要么必须抛出反射异常,要么必须在方法中处理它们。此外,这需要valueClass
提供无参数构造函数。或者,您可以简单地传递应该使用的默认值。
Java 8 update
这已经在其他答案中提到过,但为了完整起见,我将在这里添加信息。
作为Java 8的默认方法computeIfAbsent(key, mappingFunction)
基本上做同样的事情,例如,如果值类是BigDecimal
,它可能看起来像这样:
BigDecimal value = map.computeIfAbsent(key, k -> new BigDecimal("123.456"));
该方法的实现类似于上面定义的safeGet(...)
,但更灵活,可以直接在map实例中使用,并且经过更好的测试。因此,如果可能的话,我建议使用computeIfAbsent()
。
您可以使用来自Eclipse Collections的MutableMap和getIfAbsentPut()
,它们返回映射到键的值,或者插入给定值并在没有映射到键的情况下返回给定值。
您可以使用方法引用来创建一个新的Object
:
MutableMap<String, Object> map = Maps.mutable.empty();
Object value = map.getIfAbsentPut("key", Object::new);
或者你可以直接新建一个Object
:
MutableMap<String, Object> map = Maps.mutable.empty();
Object value = map.getIfAbsentPut("key", new Object());
在第一个示例中,只有当没有值映射到键时才会创建对象。
在第二个示例中,无论如何都将创建对象。
注意:我是Eclipse Collections的贡献者。
如果在任何情况下你需要在地图中获取默认数据如果它不存在
map.getOrDefault(key, defaultValue);
javadocs
EDIT:请注意,下面提到的功能早就被弃用了,应该使用CacheBuilder来代替。
Guava库有一个"计算地图",参见MapMaker.makeComputingMap(Function)。Map<String, Object> map = new MapMaker().makeComputingMap(
new Function<String, Object>() {
public String apply(Stringt) {
return new Object();
}
});
如果需要多次使用Function,将其提取到一个实用程序类中,然后像这样创建Map(其中MyFunctions.NEW_OBJECT
是静态Function实例):
Map<String, Object> map = new MapMaker()
.makeComputingMap(MyFunctions.NEW_OBJECT);
也许我没有看到整个问题,但是使用继承或组合将这种行为添加到Map对象中如何?