java 向 Guava ImmutableList 添加和删除项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12937938/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Adding and removing items to a Guava ImmutableList
提问by Sean Patrick Floyd
In Guava, is there an efficient way to add or remove items to an ImmutableList
(creating new Lists in the process, of course).
在 Guava 中,是否有一种有效的方法来添加或删除项目ImmutableList
(当然是在此过程中创建新列表)。
The simplest way I can come up with is this:
我能想到的最简单的方法是:
private ImmutableList<String> foos = ImmutableList.of();
public void addFoo(final String foo) {
if (this.foos.isEmpty()) {
foos = ImmutableList.of(foo);
} else {
foos = ImmutableList.<String>builder().addAll(foos).add(foo).build();
}
}
public void removeFoo(final String foo) {
final int index = this.foos.indexOf(foo);
if (index > -1) {
final Builder<String> builder = ImmutableList.<String>builder();
if (index > 0) builder.addAll(this.foos.subList(0, index));
final int size = this.foos.size();
if (index < size - 1) builder.addAll(this.foos.subList(index+1, size));
this.foos = builder.build();
}
}
What I would like to avoid doing is this:
我想避免做的是:
public void removeFoo(final String foo) {
final ArrayList<String> tmpList = Lists.newArrayList(this.foos);
if(tmpList.remove(foo))this.foos=ImmutableList.copyOf(tmpList);
}
But unfortunately it is so much simpler than any Guava-only method I can think of. Have I missed something?
但不幸的是,它比我能想到的任何仅使用 Guava 的方法简单得多。我错过了什么吗?
采纳答案by maaartinus
The ConcurrentModificationException
isn't really related to concurrency and synchronization. Accessing a mutable List
concurrently might corrupt it and/or throw the exception (be prepared to all 3 possibilities). You code can't fail this way, but with multithreading it doesn't work either:
在ConcurrentModificationException
是不是真的与并发性和同步。同时访问一个可变List
变量可能会破坏它和/或抛出异常(准备好所有 3 种可能性)。您的代码不会以这种方式失败,但使用多线程它也不起作用:
- Without synchronization and without
foos
beingvolatile
, there's no guarantee that another thread will ever see the changes you've made. - Even with
volatile
, it can happen that some changes get lost, e.g., when two threads add an item tofoos
, both of them can start with the original value and then the one writing last wins (and only its item gets added).
- 没有同步和
foos
bevolatile
,不能保证另一个线程会看到你所做的更改。 - 即使使用
volatile
,也可能会丢失一些更改,例如,当两个线程向 中添加一个项目时foos
,它们都可以从原始值开始,然后最后写入的那个获胜(并且只有它的项目被添加)。
The code you're trying to avoid is nothing to be avoided.
您试图避免的代码是无可避免的。
- "I have to create superfluous intermediate collections"- yes, but there's no free lunch:
- determine the size of the result in advance, which means an additional iteration through the whole list
- or allocate a large enough array and copy the needed range in the resulting list
- or allocate a large enough array and use only part of it (saving time and wasting memory)
- or create an immutable view (saving both time and memory, but possibly losing time later)
- AFAIK Frank's answer implements the first possibility, which is fine if the predicate is fast.
- "I have to mix java.util Collections with guava ImmutableCollections, while I'd like to stick to one paradigm."- yes, but for mutating a collection a mutable collection is needed. The
ImmutableList.Builder
covers just the most common cases allowing to handle them in a compact way.
- “我必须创建多余的中间系列”——是的,但天下没有免费的午餐:
- 预先确定结果的大小,这意味着对整个列表进行额外的迭代
- 或分配一个足够大的数组并在结果列表中复制所需的范围
- 或者分配一个足够大的数组并只使用其中的一部分(节省时间并浪费内存)
- 或者创建一个不可变的视图(节省时间和内存,但可能会浪费时间)
- AFAIK Frank's answer实现了第一种可能性,如果谓词很快,这很好。
- “我必须将 java.util Collections 与 guava ImmutableCollections 混合使用,而我想坚持一种范式。” - 是的,但是为了改变集合,需要一个可变集合。在
ImmutableList.Builder
仅涉及最常见的情况下允许处理它们以紧凑的方式。
You might want to have a look at persistent collections, which are optimized for such operations. However, you shouldn't expect e.g. the persistent list to be as fast as an ArrayList
or ImmutableList
.
您可能想查看针对此类操作进行了优化的持久集合。但是,您不应该期望持久列表与ArrayList
or一样快ImmutableList
。
回答by Frank Pavageau
You can remove by filtering, which doesn't create an intermediate ArrayList
or builder, and only traverses the list once:
您可以通过过滤删除,这不会创建中间ArrayList
或构建器,并且只遍历列表一次:
public void removeFoo(final String foo) {
foos = ImmutableList.copyOf(Collections2.filter(foos,
Predicates.not(Predicates.equalTo(foo)));
}
For adding, I don't see a better solution.
对于添加,我没有看到更好的解决方案。