Groovy Map.get(key,default)会改变地图

Hug*_*lle 4 groovy dictionary mutability

我有以下Groovy脚本:

mymap = ['key': 'value']
println mymap

v = mymap.get('notexistkey', 'default')

println v
println mymap
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我得到以下控制台输出:

[key:value]
default
[key:value, notexistkey:default]
Run Code Online (Sandbox Code Playgroud)

我很惊讶,当调用mymap.get('notexistkey', 'default')第二个参数是一个默认值时,当给定的键不存在时,该键notexistkey被添加到我称之为方法的地图上.为什么?这是预期的行为吗?我怎样才能防止这种突变?

Szy*_*iak 8

使用Java Map.getOrDefault(key, value)代替:

mymap = ['key': 'value']
println mymap

v = mymap.getOrDefault('notexistingkey', 'default')

println v
println mymap
Run Code Online (Sandbox Code Playgroud)

输出:

[key:value]
default
[key:value]
Run Code Online (Sandbox Code Playgroud)

Groovy SDK添加了Map.get(key, default)via DefaultGroovyMethods.get(map, key, default),如果你看看Javadoc说你会理解这种行为是预期的:

在Map中查找给定键的项并返回值 - 除非给定键没有条目,在这种情况下将默认值添加到地图并返回该值.

这就是这个方法的实现:

/**
 * Looks up an item in a Map for the given key and returns the value - unless
 * there is no entry for the given key in which case add the default value
 * to the map and return that.
 * <pre class="groovyTestCase">def map=[:]
 * map.get("a", []) &lt;&lt; 5
 * assert map == [a:[5]]</pre>
 *
 * @param map          a Map
 * @param key          the key to lookup the value of
 * @param defaultValue the value to return and add to the map for this key if
 *                     there is no entry for the given key
 * @return the value of the given key or the default value, added to the map if the
 *         key did not exist
 * @since 1.0
 */
public static <K, V> V get(Map<K, V> map, K key, V defaultValue) {
    if (!map.containsKey(key)) {
        map.put(key, defaultValue);
    }
    return map.get(key);
}
Run Code Online (Sandbox Code Playgroud)

这是一个非常古老的概念(自Groovy 1.0以来).但是我建议不要使用它 - 这个.get(key, default)操作既不是原子的,也不是同步的.和存在的问题,当你使用它的启动ConcurrentMap是专为并发访问-这种方法打破了合同,因为之间没有同步containsKey,put最终和get电话.