I read the answers to this question: Will Java 8 create a new List after using Stream "filter" and "collect"?
But it did not quite match my experience... I think. And I'm just wanting to make sure I'm clear on the situation.
Consider the following code (which can be run on https://www.tutorialspoint.com/compile_java_online.php):
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
public class ArrayPlay {
public static class Person {
private String first;
private String last;
private int id;
private State state;
private boolean thing;
public Person(String first, String last, int id, boolean isThing) {
this.id = id;
this.first = first;
this.last = last;
this.thing = isThing;
}
public void setFirst(String first) { this.first = first; }
public String getFirst() { return first; }
public void setLast(String last) { this.last = last; }
public String getLast() { return last; }
public void setId(int id) { this.id = id; }
public int getId() { return id; }
public void setIsThing(boolean thing) { this.thing = thing; }
public boolean isThing() { return thing; }
public void setState(State state) { this.state = state; }
public State getState() { return this.state; }
@Override
public String toString() {
return String.valueOf(id) + ": " + first + " " + last +
(thing ? " and has thing" : "") +
(state != null ? " and is from " + state.getStateName() : "");
}
}
public static class State {
private String stateName;
private String stateCode;
private String country;
public State() { }
public String getStateName() { return stateName; }
public void setStateName(String name) { this.stateName = name; }
public String getStateCode() { return stateCode; }
public void setStateCode(String code) { this.stateCode = code; }
public String getCountry() { return country; }
public void setCountry(String country) { this.country = country; }
public static State newStateCode(String code) {
State state = new State();
state.setStateCode(code);
return state;
}
public static final class Builder {
private State state;
private Builder() { state = new State(); }
public static Builder aState() { return new Builder(); }
public Builder withName(String name) { state.setStateName(name); return this;}
public Builder withCode(String code) { state.setStateCode(code); return this;}
public Builder withCountry(String country) { state.setCountry(country); return this;}
public State build() { return state; }
}
}
public static void main(String[] args) {
List<Person> people = new ArrayList<Person>() {{
add(new Person("ffej", "llensog", 13482839, true));
add(new Person("knarf", "knarfson", 39940000, false));
add(new Person("Mary", "Contrary", 82233888, true));
}};
System.out.println("\nSet State for filtered Persons");
List<Person> hasThing = people.stream().filter(p -> p.isThing()).collect(Collectors.toList());
System.out.println("Before setting state.");
people.forEach(p -> System.out.println("people: " + p));
hasThing.forEach(p -> p.setState(State.Builder.aState().withName("Alabama").build()));
System.out.println("After setting state.");
people.forEach(p -> System.out.println("people: " + p));
hasThing.forEach(p -> System.out.println("hasThing: " + p));
}
}
The result I expect is the following:
et State for filtered Persons
Before setting state.
people: 13482839: Daphne llensog and has thing
people: 39940000: Daphne knarfson
people: 82233888: Daphne Contrary and has thing
After setting state.
people: 13482839: Daphne llensog and has thing
people: 39940000: Daphne knarfson
people: 82233888: Daphne Contrary and has thing
hasThing: 13482839: Daphne llensog and has thing and is from Alabama
hasThing: 82233888: Daphne Contrary and has thing and is from Alabama
But the actual result that I'm getting is:
et State for filtered Persons
Before setting state.
people: 13482839: Daphne llensog and has thing
people: 39940000: Daphne knarfson
people: 82233888: Daphne Contrary and has thing
After setting state.
people: 13482839: Daphne llensog and has thing and is from Alabama
people: 39940000: Daphne knarfson
people: 82233888: Daphne Contrary and has thing and is from Alabama
hasThing: 13482839: Daphne llensog and has thing and is from Alabama
hasThing: 82233888: Daphne Contrary and has thing and is from Alabama
For some reason, when I run the setState on hasThing's forEach, it is also modifying the objects in people. And this doesn't make sense to me if filter(...).collect() creates a new list. Is there a good explanation for this action that I'm not understanding?
