将对象(通过引用)传递给方法时,对象不会更新(通过 Lambdas 过滤器)

Object is not updated (by Lambdas filter) when passing it (by reference) to a method

我正在使用 java8SpringBoot 2JPA2,但我 运行 遇到了一个奇怪的问题。假设如下代码:

public void doSome() {
    List<Integer> arr = new ArrayList<>(Arrays.asList(1,2,3,4,5));
    List<Integer> arr2 = new ArrayList<>(Arrays.asList(1,2,3,4));

    otherMethod(arr, arr2);
    System.out.println(arr);
}

在同一个 class 我有 otherMethod() 和这个版本:

public void otherMethod(List<Integer> arr, List<Integer> arr2) {
    arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
    System.out.println(arr); // here print just 5
}

当代码流将我带回到 doSome():

System.out.println(arr); // print [1,2,3,4,5]

如果我按如下方式更改 otherMethod()

public void otherMethod(List<Integer> arr, List<Integer> arr2) {
//    arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());
    arr.removeIf(x -> x < 3);
    System.out.println(arr); // print [3,4,5]
}

并且更改会影响我通过引用传递的对象,在 doSome() 方法中我看到:

System.out.println(arr); // print [3,4,5]

我不明白为什么 arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList()) 更改不会影响我通过引用传递的对象。

我哪里错了?

首先我想说的是Java只有值传递,没有引用传递。

这个post

中明确提到了这一点

让我们遍历您的代码。

public void doSome() {
    //Memory is allocated in heap for two new array lists 
    // and the address of each copied to arr, arr2 variables respectively.

    List<Integer> arr = new ArrayList<>(Arrays.asList(1,2,3,4,5)); 
    List<Integer> arr2 = new ArrayList<>(Arrays.asList(1,2,3,4));

    // Here you are passing the value stored in arr and arr2 variables.
    // And the called method copies the values to another set of variables defined as parameters in the called method.
    otherMethod(arr, arr2);

    // Print the content of the object(ArrayList) whose address is stored in arr variable.
    System.out.println(arr);
} 

public void otherMethod(List<Integer> arr, List<Integer> arr2) {
    // When this method is called, Two variable are created. The value of parameters from the calling method will be copied to these variables.

    //Here Collectors.toList() creates a new list after going through stream and filter.
    // And then you are assigning the new list to arr varibable.
    //Which means arr stores the reference to newly created list and loses the reference to original list.
    // This statement will not affect the arr variable in doSome()
    arr = arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList());

    //Printing the value of list and this list is different from the called list
    System.out.println(arr); // here print just 5
}
其他方法中的

arr.removeIf(x -> x < 3);doSome() 中生效,因为 arr 仍指向相同的堆位置。

如果你想在doSome()方法中修改列表,你有两个选择。

  1. return新的arraylist形成调用方法并在调用方法中使用它。
  2. 或者将新的筛选列表复制到另一个临时变量。清除 arr 变量指向的列表,然后将过滤列表中的所有项目添加到 arr 变量。