I'm using java8
, SpringBoot 2
, and JPA2
and I'm run in a strange problem. Suppose the following code:
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);
}
In the same class I have the otherMethod()
and with this version:
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
}
When code flow bring me back to doSome()
:
System.out.println(arr); // print [1,2,3,4,5]
If I change my otherMethod()
as follows:
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]
}
and the changes affect the Object I have passed by reference, in doSome()
method I see:
System.out.println(arr); // print [3,4,5]
I don't understand why with arr.stream().filter(x -> !arr2.contains(x)).collect(Collectors.toList())
changes doesn't affect my Object passed by reference.
where am I wrong?
This is clearly mentioned in this post
Lets walkthrough your code.
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);
in Other method takes effect in doSome()
because, the arr is still pointing to same heap location.
If you want the the modified list in doSome()
method, you have two options.