简体   繁体   English

Java 8 Lambda表达式多次更改Collection

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM