【发布时间】:2012-02-01 05:55:31
【问题描述】:
我们目前正在将 Guava 用于其不可变集合,但我惊讶地发现他们的地图没有方法可以轻松创建新地图,只需稍作修改。最重要的是,他们的构建器不允许为键分配新值或删除键。
因此,如果我只想修改一个值,我希望能够这样做:
ImmutableMap<Guid, ImmutableMap<String, Integer>> originalMap = /* get the map */;
ImmutableMap<Guid, ImmutableMap<String, Integer>> modifiedMap =
originalMap.cloneAndPut(key, value);
Guava 期待我这样做:
ImmutableMap<Guid, ImmutableMap<String, Integer>> originalMap = /* get the map */;
Map<Guid, ImmutableMap<String, Integer>> mutableCopy = new LinkedHashMap<>(originalMap);
mutableCopy.put(key, value);
originalMap = ImmutableMap.copyOf(mutableCopy);
/* put the map back */
通过这样做,我得到了一份带有我想要的修改的新地图副本。原始副本未受影响,我将使用原子引用将其放回原处,因此整个设置是线程安全的。
只是很慢。
这里有很多在幕后进行的浪费复制。假设地图中有 1,024 个桶。那是 1,023 个桶,您不必要地重新创建(每个也两次),而您可以按原样使用这些不可变的桶并只克隆其中一个。
所以我猜:
有没有为这类事情埋在某处的 Guava 实用方法? (它不在地图或 ImmutableMap.Builder 中。)
还有其他的 Java 库可以做到这一点吗?我的印象是 Clojure 有这种东西,但我们还没有准备好切换语言......
【问题讨论】:
-
如果您愿意,请提交功能请求,但您可能真的在寻找合适的功能数据结构库。
-
是的。这是可以做到的——这就是函数式语言所做的——但这不是 Guava 的用途。番石榴的例如
ImmutableMap是基于散列的,不支持高效更新,查询速度也有很大的代价。 -
改写:Guava 的不可变集合是为快速查询/迭代和最小的内存消耗而构建的。这意味着散列和数组,它们不会让您支持有效的非破坏性更新。
-
@Louis Guava 仍然可以支持 API
originalMap.cloneAndPut(key, value)或originalMap.asBuilder().put(key, value)。 -
这是线性开销,让用户认为它比实际更快是非常冒险的......你的代码并没有真正让我意识到这是一个缓慢的解决方法。
标签: java map immutability guava