我正在使用Guava 18.0的同步SetMultimap
该集合声明如下
private SetMultimap<String, Foo> fooMultimap;
private StatusService() {
this.fooMultimap = Multimaps.synchronizedSetMultimap(HashMultimap.<String, Foo>create());
}
StatusService是一个弹簧引导@Service
,当然它被视为单例。 SetMultimap是一个包含的多图
其中Foo是具有多个属性的模型。
因此我有以下方法:
/* remove element */
public void removeFoo(String fooId, Foo foo) {
fooMultimap.remove(fooId, foo);
}
以及
/* remove element by unique property(element path) */
public void removeByPath(String path) {
Lists.newArrayList(getAllFoos().values()).stream()
.filter(Objects::nonNull)
.filter(foo -> Optional.ofNullable(foo.getPath())
.filter(fooPath -> fooPath.contains(path))
.isPresent()
).forEach(filteredFoo -> removeFoo(img.getId(), img));
}
}
和getAllFoos()方法如下
public SetMultimap<String, Foo> getAllFoos() {
return this.fooMultimap;
}
我无法理解的是为什么Guava没有从多图中删除元素,也许我做错了什么,我尝试了所有可能的组合.values()
或.asMap()
或{{ 1}}没有任何运气。
有人可以解释一下从番石榴.entries()
中删除关键值条目的最佳方法是什么?
这是一个重现我的问题的例子,如果我改变一个对象,那么我就不能再删除条目了。当我改变图像的状态时会发生改变
synchronized SetMultimap
答案 0 :(得分:1)
由于Multimap<K,V>
是一种Map<K,Set<V>>
(虽然没有实现它),但它具有相似的语义,即您不能在插入后以影响其hashcode / equality的方式修改元素。< / p>
除此之外,你遇到了iterate-then-lookup反模式。这不仅效率低,而且在与迭代器一起使用时会导致ConcurrentModificationException
,迭代器不支持对它们正在迭代的集合的修改(除了那些通过迭代器本身进行的修改)。
在大多数情况下,有简单的替代方案,例如而不是
public static void removeByPath(String path) {
mm.get("2").stream()
.filter(Objects::nonNull)
.filter(image -> Optional.ofNullable(image.getPath())
.filter(imagePath -> imagePath.contains(path)
&& image.getStatus().equals(ImageState.DONE))
.isPresent()
).forEach(img -> {
mm.values().remove(img);
});
}
您只需使用
即可public static void removeByPath(String path) {
mm.get("2").removeIf(
image -> Optional.ofNullable(image).map(Image::getPath)
.filter(imagePath -> imagePath.contains(path)
&& image.getStatus().equals(ImageState.DONE))
.isPresent()
);
}
避免过时的查找,不会抛出ConcurrentModificationException
。请注意,虽然现在可以使用,但即使哈希代码已更改,在插入后更改哈希代码仍然不是正确的用法,并且后续查找可能会失败的事实会让您感到惊恐。