java 中的函数式编程:克隆与变异。是好是坏?
Functional programming in java: Cloning Vs Mutating. Good or bad?
变异:
"transformEmployeeNameToUpperCase" 将员工姓名转换为大写的函数。
List<Employee> employeesStartsWithDInUppercase1 = employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.map(Main::transformEmployeeNameToUpperCase)
.collect(Collectors.toList());
public static Employee transformEmployeeNameToUpperCase(Employee employee){
employee.setName(employee.getName().toUpperCase());
return employee;
}
克隆:
"createEmployeeWithUpperCaseName" 对姓名大写的新员工起作用。
List<Employee> employeesStartsWithDInUppercase2 = employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.map(Main::createEmployeeWithUpperCaseName)
.collect(Collectors.toList());
public static Employee createEmployeeWithUpperCaseName(Employee e){
return new Employee( e.getId(), e.getName().toUpperCase(), e.getDesignation(), e.getAge());
}
Does "createEmployeeWithUpperCaseName" follow rule 1(above) as they say
是:员工没有被修改
In case of "transformEmployeeNameToUpperCase", does it follow rule 2(above)?
是的,尽管该规则使用了不正确的术语。它创建一个对象,而不是一个变量。您不能创建变量。
Is it good practice to use transformEmployeeNameToUpperCase way?
不,至少不是你这样做的方式。修改可变对象本身并没有什么坏处:它们是可变的是有原因的。但是 map()
操作不应该修改它的输入和 return 它。你在曲解它的目的。您的代码的未来 reader 不会期望映射操作改变其输入,因此您会让您的代码做意想不到的事情,从而导致错误 and/or 误解。这样做会更好:
employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.forEach(e -> e.setName(e.getName().toUpperCase()));
这样一来,就清楚了管道的作用是对列表的元素产生副作用。而且它也不会创建(可能)无用的列表副本。
同意@JB Nizet 的观点,但如果您不想更改原始对象但想将员工姓名更改为大写。使用对象克隆。
伪代码:
List<Employee> employeeWithUpperCaseName = employees.parallelStream()
.filter(e -> e.getName().startsWith("D"))
.map(x -> {
Employee s = null;
try {
s = (Employee) x.clone();
s.setName(x.getName().toUpperCase());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
} finally {
return s;
}
})
.collect(Collectors.toList());
你可以写得更好
变异:
"transformEmployeeNameToUpperCase" 将员工姓名转换为大写的函数。
List<Employee> employeesStartsWithDInUppercase1 = employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.map(Main::transformEmployeeNameToUpperCase)
.collect(Collectors.toList());
public static Employee transformEmployeeNameToUpperCase(Employee employee){
employee.setName(employee.getName().toUpperCase());
return employee;
}
克隆:
"createEmployeeWithUpperCaseName" 对姓名大写的新员工起作用。
List<Employee> employeesStartsWithDInUppercase2 = employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.map(Main::createEmployeeWithUpperCaseName)
.collect(Collectors.toList());
public static Employee createEmployeeWithUpperCaseName(Employee e){
return new Employee( e.getId(), e.getName().toUpperCase(), e.getDesignation(), e.getAge());
}
Does "createEmployeeWithUpperCaseName" follow rule 1(above) as they say
是:员工没有被修改
In case of "transformEmployeeNameToUpperCase", does it follow rule 2(above)?
是的,尽管该规则使用了不正确的术语。它创建一个对象,而不是一个变量。您不能创建变量。
Is it good practice to use transformEmployeeNameToUpperCase way?
不,至少不是你这样做的方式。修改可变对象本身并没有什么坏处:它们是可变的是有原因的。但是 map()
操作不应该修改它的输入和 return 它。你在曲解它的目的。您的代码的未来 reader 不会期望映射操作改变其输入,因此您会让您的代码做意想不到的事情,从而导致错误 and/or 误解。这样做会更好:
employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.forEach(e -> e.setName(e.getName().toUpperCase()));
这样一来,就清楚了管道的作用是对列表的元素产生副作用。而且它也不会创建(可能)无用的列表副本。
同意@JB Nizet 的观点,但如果您不想更改原始对象但想将员工姓名更改为大写。使用对象克隆。
伪代码:
List<Employee> employeeWithUpperCaseName = employees.parallelStream()
.filter(e -> e.getName().startsWith("D"))
.map(x -> {
Employee s = null;
try {
s = (Employee) x.clone();
s.setName(x.getName().toUpperCase());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
} finally {
return s;
}
})
.collect(Collectors.toList());
你可以写得更好