【问题标题】:Does Java's stream filter create a new list or point to the original list?Java 的流过滤器是创建新列表还是指向原始列表?
【发布时间】:2021-04-15 17:36:12
【问题描述】:

我阅读了这个问题的答案:Will Java 8 create a new List after using Stream "filter" and "collect"?

但它与我的经验不太相符……我想。我只是想确保我清楚情况。

考虑以下代码(可以在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));
    }
}

我期望的结果如下:

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

但我得到的实际结果是:

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

由于某种原因,当我在hasThingforEach 上运行setState 时,它也在修改people 中的对象。如果filter(...).collect() 创建一个新列表,这对我来说没有意义。对我不理解的这个动作有很好的解释吗?

【问题讨论】:

    标签: java arraylist java-stream


    【解决方案1】:

    看起来很简单。 List 将是新的 ArrayList 实例。不是列表包含的对象。由于您修改了列表包含的实例,因此这两个列表都会显示为已修改

    它也在修改人的对象。这并没有使 我觉得 filter(...).collect()

    当然它会修改那些对象。列表只是一个包含对对象实例的引用的集合。

    在您的情况下,您有 2 个集合(列表),它们包含对相同实例的引用。使用 1 个列表修改对象的状态将反映到两个列表。

    这是一个简单的图形表示

    使用 ref2 修改实例的状态它实际上修改了 ref4 指向的同一个实例

    【讨论】:

    • 好吧,我很困惑“新列表”并不意味着“为数据保留新的内存”。即“新列表”指向数据的相同旧内存位置。 (隐藏指针操作的乐趣。)
    猜你喜欢
    • 1970-01-01
    • 2015-10-23
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多