Get (key)-如果 key 不存在,自动执行 put (key)和 return?

我厌倦了以下的模式:

value = map.get(key);
if (value == null) {
value = new Object();
map.put(key, value);
}

此示例只涉及到在具有表示多维结构的嵌套映射时要编写的额外代码的表面。

I'm sure something somewhere exists to avoid this, but my Googling efforts yielded nothing relevant. Any suggestions?

89093 次浏览

那个

java.util.concurrent.ConcurrentMap

以及 Java 8

Java.util.Map

已经

putIfAbsent(K key, V value)

which returns the existing value, and if that is null inserts given value. So if no value exists for key returns 无效 and inserts the given value, otherwise returns existing value

如果需要对值进行惰性计算,则存在

computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)

The problem with this pattern is that you'd have to somehow define the value that should be used in case the get() returns 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

这个问题已经在其他答案中提到过,但是为了完整起见,我还要在这里添加一些信息。

在 Java8中有一个默认的方法 computeIfAbsent(key, mappingFunction),它基本上做同样的事情,例如,如果值类是 BigDecimal,它可以看起来像这样:

BigDecimal value = map.computeIfAbsent(key, k -> new BigDecimal("123.456"));

该方法的实现类似于上面定义的 safeGet(...),但是更加灵活,可以直接在 map 实例中获得,并且经过了更好的测试。因此,如果可能的话,我建议使用 computeIfAbsent()

编辑: 注意,下面提到的特性已经过时了,应该使用 CacheBuilder

Guava库有一个“ 电脑地图”,参见 Make ComputingMap (函数)

Map<String, Object> map = new MapMaker().makeComputingMap(
new Function<String, Object>() {
public String apply(Stringt) {
return new Object();
}
});

如果您多次需要 Function,将其提取到一个实用程序类中,然后像下面这样创建 Map (其中 MyFunctions.NEW_OBJECT是静态 Functional 实例) :

Map<String, Object> map = new MapMaker()
.makeComputingMap(MyFunctions.NEW_OBJECT);

也许我没有看到整个问题,但是如何使用继承或组合将这种行为添加到 Map 对象呢?

您可以使用 Eclipse 集合中的 MutableMapgetIfAbsentPut()来返回映射到键的值,或者如果没有映射到键的值,则插入给定的值并返回给定的值。

您可以使用一个方法引用来创建一个新的 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());

在第一个示例中,仅当没有映射到键的值时才创建对象。

在第二个示例中,无论如何都将创建对象。

Note: I am a contributor to Eclipse Collections.

Java8为 地图添加了很好的方法: 计算计算机现在没有

为了达到你的目的:

Object existingOrCreated = map.computeIfAbsent(key, (k) -> new Object());

如果在任何情况下,如果地图中不存在默认数据,则需要获取该数据

map.getOrDefault(key, defaultValue);

Javadocs