Java .原始对象的映射和变异';内容

Java .原始对象的映射和变异';内容,java,java-8,Java,Java 8,考虑一下这个代码 List<Employee> employees = new ArrayList<Employee>(); employees.add(new Employee("A", "B")); employees.add(new Employee("A1", "B1")); employees.stream().map(e-> { e.setfName("M

考虑一下这个代码

List<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee("A", "B"));
employees.add(new Employee("A1", "B1"));
    
employees.stream().map(e-> { e.setfName("Mr. " + e.getfName()); return e; }); // 1. DOES NOT mutate employees' content

employees.stream().map(e-> { e.setfName("Mr. " + e.getfName()); return e; }).collect(Collectors.toList()); // 2. DOES mutate employees' content

employees.stream().map(e-> new Employee ("Mrs. " + e.getfName(), e.getlName())).collect(Collectors.toList()); // 3. DOES NOT put new objects in original list
List employees=new ArrayList();
添加(新员工(“A”、“B”);
添加(新员工(“A1”、“B1”);
employees.stream().map(e->{e.setfName(“Mr.”+e.getfName());返回e;});//1.不会改变员工的内容
employees.stream()2.是否会改变员工的内容
employees.stream()3.不将新对象放入原始列表中

不确定我是否理解这种行为的原因。如果流确实创建了一个单独的内存,那么2是否也不应该改变原始列表的内容?

了解流的一个重要方面是。如果
map
值,则仅当从流中检索值时才会调用映射函数
collect
ing一个流是使用值并强制突变的一种方法,这就是为什么第二个示例会对列表进行突变,而第一个示例不会。第三个示例没有对对象进行适当的变异,而是为每个对象创建一个新的
Employee
,因此它创建了一个与原始列表无关的新克隆列表

employees.stream().map(e-> { e.setfName("Mr. " + e.getfName()); return e; }); // 1. DOES NOT mutate employees' content
第1行没有改变员工的内容,因为它根本没有做任何事情。在调用终端操作之前,不会计算流

第2行创建了一个新列表来保存更新的员工,但原始员工会被更新——因此您有两个可独立修改的列表,其中包含完全相同的员工和完全相同的数据,如果没有其他员工,则无法修改其中一个。因此,根据第2行的结果,您可以
添加
员工
对象,而不修改
员工
,但如果不修改原始员工,则无法修改该
列表中的员工(因为他们是相同的员工)


只有第3行创建新的
Employee
对象,这些对象独立于原始对象而存在。

好的,这很有帮助。但是,如何使用.map来更改原始集合项,而不产生重复列表?e、 是否有一个终端操作我可以调用而不创建新的列表(例如,像在Javascript中)。或者,我完全没有在错误地使用/比较.map与其他动态/函数式语言吗?如果您的目标是更改原始集合项而不是创建新列表,那么请使用
.forEach
而不是
.map
。那么,我们不应该只在forEach中放置纯函数(lambda)吗?这意味着不改变它的闭包吗?不。forEach
的目的是做与此相反的事情,只有不纯函数<代码>映射
用于纯函数。根据其定义,
forEach
在传递纯函数时不做任何事情
Consumer
是传递给
forEach
的lambda类型。