[英]Java 8 lambda expression changes Collection multiple times
I have the following classes: 我有以下课程:
Doer, which just executes the run-method of the Runnable (will be a lambda): Doer,它仅执行Runnable的运行方法(将是lambda):
public class Doer {
final Runnable runnable;
public Doer(final Runnable runnable) {
this.runnable = runnable;
}
public void doSomething() {
runnable.run();
}
}
Storage, which is a Observable number store: 存储,这是一个可观察的数字存储:
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
public class Storage extends Observable {
final List<Integer> storage;
public Storage() {
this.storage = new ArrayList<>();
}
void add(int number) {
storage.add(number);
setChanged();
notifyObservers(number);
}
public List<Integer> getStorage() {
return storage;
}
}
Filter, preventing the Doer from doing so much ;) 过滤,防止Doer做太多事情;)
import java.util.Observable;
import java.util.Observer;
public class Filter implements Observer {
final Doer doer;
int counter;
final int nth;
public Filter(int nth, Storage store, Doer doer) {
this.doer = doer;
this.nth = nth;
store.addObserver(this);
}
@Override
public void update(Observable o, Object arg) {
counter++;
if (counter == nth)
doer.doSomething();
}
}
Now consider the following Unit Test: 现在考虑以下单元测试:
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class FilterTest {
@Test
public void testStore() throws Exception {
List<Collection<Integer>> numbers = new ArrayList<>();
Storage store = new Storage();
Filter filter = new Filter(2, store, new Doer(() -> {
numbers.add(store.getStorage());
System.out.println(numbers);
}));
System.out.println(numbers);
store.add(1);
System.out.println(numbers);
store.add(2);
System.out.println(numbers);
store.add(3);
System.out.println(numbers);
}
}
It produces the results: 它产生结果:
[]
[]
[[1, 2]]
[[1, 2]]
[[1, 2, 3]]
I really do not get the last line, why is the 3 now in numbers, since numbers.add(3) has not been executed in the lambda? 我真的没有得到最后一行,为什么现在的数字是3,因为在lambda中没有执行numbers.add(3)?
The lambda is called only once. 该lambda仅被调用一次。 It's adding the
List<Integer>
that's inside store
to numbers
. 它将
store
内部的List<Integer>
添加到numbers
。
Note that the lambda is not making a copy of the List<Integer>
in store
. 请注意,lambda不会在
store
复制List<Integer>
。 So, numbers
contains a reference to the same List<Integer>
as what is in store
. 因此,
numbers
包含与store
相同的List<Integer>
的引用。
If you add more numbers to the List<Integer>
in store
, you see those changes also in numbers
, because the content of numbers
is a reference to the same List<Integer>
. 如果添加了更多数量的
List<Integer>
在store
,你会看到这些变化也在numbers
,因为内容numbers
是相同的参考List<Integer>
。
So when you do store.add(3);
因此,当您执行
store.add(3);
and then print the content of numbers
, you'll also see the 3
in there. 然后打印
numbers
内容,您还将在其中看到3
。
Try making a copy of the collection when you add it to numbers
in the lambda, and see the difference: 将集合添加到lambda中的
numbers
时,请尝试制作该集合的副本,并观察其中的区别:
Filter filter = new Filter(2, store, new Doer(() -> {
numbers.add(new ArrayList<>(store.getStorage()));
System.out.println(numbers);
}));
Output: 输出:
[]
[]
[[1, 2]]
[[1, 2]]
[[1, 2]]
Without knowing what your code is really supposed to do, I assume your numbers
collection is not declared correctly: 不知道您的代码真正应该做什么,我假设您的
numbers
集合未正确声明:
List<Collection<Integer>> numbers = new ArrayList<>();
This is a list of collections of integers, so every element of your list is supposed to be a collection by itself. 这是一个整数集合的列表,因此,列表中的每个元素本身都应该是一个集合。 Instead, it should probably be just a list of numbers:
相反,它可能应该只是数字列表:
List<Integer> numbers = new ArrayList<>();
So you will also have to change the Runnable
too, as you don't want to add the entire storage to your list but just the content of the storage: 因此,您也必须更改
Runnable
,因为您不想将整个存储添加到列表中,而只是将存储的内容添加到列表中:
() -> {
numbers.addAll(store.getStorage());
System.out.println(numbers);
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.