Java流映射修改非内置类的自定义类对象

Java流映射修改非内置类的自定义类对象,java,java-8,java-stream,Java,Java 8,Java Stream,内干管: class Employee { public String name; public Integer age; public Employee(String n, int age) { this.name = n; this.age = age; } public String toString() { return this.name+":"+this.age; } } ArrayL

内干管:

class Employee {

    public String name;
    public Integer age;
    public Employee(String n, int age) {
        this.name = n;
        this.age = age;
    }
    public String toString() {
        return this.name+":"+this.age;
    }
}
ArrayList list=new ArrayList();
列表。添加(新员工(“NameA”,10));
增加(新员工(“姓名B”,25));
添加(新员工(“NameC”,30));
列表。添加(新员工(“已命名”,45));
添加(新员工(“姓名”,50));
系统输出打印项次(列表)//[姓名A:10,姓名B:25,姓名C:30,姓名45,姓名E:50]
list.stream().filter(e->e.age%10==0).map(e->e.name+=“更改”).collect(Collectors.toList());
系统输出打印项次(列表)//[姓名更改:10,姓名B:25,姓名更改:30,姓名更改:45,姓名更改:50]
ArrayList strList=新的ArrayList();
strList.添加(“1”);
strList.添加(“2”);
strList.添加(“3”);
strList.添加(“4”);
strList.添加(“5”);
System.out.println(strList)//[1, 2, 3, 4, 5]
List updatedStrList=strList.stream().map(s->s+=“CHANGE”).collect(Collectors.toList());
System.out.println(更新的strlist)//[1改变,2改变,3改变,4改变,5改变]
System.out.println(strList)//[1, 2, 3, 4, 5]
这种行为的原因是什么?
更改Employee对象的值时,该值会在原始ArrayList中更新,但更改字符串的ArrayList时,该值不会反映在原始ArrayList中

e.name+=“CHANGE”和
s->s+=“CHANGE”
之间有区别。它们都创建了一个新的
String
实例,但第一个实例将该新
String
分配给
Employee
类实例的实例变量(并因此对该实例进行变异),第二个实例将其分配给本地
String
变量


因此
e.name+=“CHANGE”
更改了原始
列表的相应实例,而
s->s+=“CHANGE”
没有更改。

问题与流无关

在这个lambda表达式中:
s->s+=“CHANGE”
,您只需重新分配局部变量
s
s+=“CHANGE”
还返回连接的结果,这解释了流显示映射值的原因。此重新分配仅在lambda表达式的局部范围内有效

但是
e.name+=“CHANGE”
更新
Employee
对象
e
的字段。这将更新原始对象本身


您应该收集映射值,而不是更新原始流元素。顺便说一句,在您的情况下,更新原始流元素甚至不是一个选项,因为您不能修改字符串对象。

传递给map()的函数不应该修改它映射的内容。它应该从作为参数的对象返回另一个对象(第二个例子使用字符串就是这样做的)
s+=“CHANGE”
不修改
s
。它创建了一个新字符串,它是
s
和“CHANGE”的串联。调用
collect(Collectors.toList())
而不捕获返回值是一种资源浪费。stream().map()允许您将对象转换为其他对象。看看这篇文章,的javadoc明确指出映射器必须是“a,function”。当你更新对象时,你违反了契约的非干涉部分。所以map函数返回一个新的流,在第一个例子中,自从Employee对象的成员值被更改后,它反映在原始列表中,但在第二个例子中没有发生同样的情况,对吗?我想我明白了,谢谢。@gagandepsing是的,
map
方法返回一个新的
Stream
,其中包含新的
String
元素。是的,在第一个示例中,您正在修改原始
员工
元素(这也会影响原始
列表
)。感谢您澄清这一点,我现在理解了这个概念。
ArrayList<Employee> list = new ArrayList<>();
list.add(new Employee("NameA", 10));
list.add(new Employee("NameB", 25));
list.add(new Employee("NameC", 30));
list.add(new Employee("NameD", 45));
list.add(new Employee("NameE", 50));

System.out.println(list);//[NameA:10, NameB:25, NameC:30, NameD:45, NameE:50]

list.stream().filter(e->e.age%10==0).map(e->e.name+="CHANGE").collect(Collectors.toList());

System.out.println(list); //[NameACHANGE:10, NameB:25, NameCCHANGE:30, NameD:45, NameECHANGE:50]


ArrayList<String> strList = new ArrayList<>();
strList.add("1");
strList.add("2");
strList.add("3");
strList.add("4");
strList.add("5");

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

List<String> updatedStrList = strList.stream().map(s->s+="CHANGE").collect(Collectors.toList());

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

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