为什么我们需要在编码时避免突变?什么是突变?
Why do we need to avoid mutations while coding? What is a mutation?
为什么第二个代码(带流的那个)比第一个更好?
第一个:
public static void main(String [] args) {
List<Integer> values = Arrays.asList(1,2,3,4,5,6);
int total = 0;
for(int e : values) {
total += e * 2;
}
第二个:
System.out.println(total);
System.out.println(
values.stream()
.map(e-> e*2)
.reduce(0, (c, e)-> c + e));
变异正在改变一个对象的状态,可以是列表,也可以是一些自定义对象。
您的特定代码不会导致列表发生任何变化,因此使用 lambda 代替普通的旧迭代没有实际好处。而且,怪我,但在这种情况下我会使用迭代方法。
有些方法说,每当您需要修改 object/collection 时,您需要 return 使用修改后的数据创建一个新的 object/collection,而不是更改原始数据。这对集合很有用,例如当您同时访问一个集合并且它正在从另一个线程更改时。
当然这可能会导致内存泄漏,因此有一些算法用于管理内存和集合的可变性,即只有更改的节点存储在内存中的另一个位置。
变异正在改变一个对象,是编程语言中的一种常见副作用。
具有功能契约的方法将始终return相同参数的相同值并且没有其他副作用(如存储文件、打印、读取).因此,即使您在函数内部改变临时值,它在外部仍然是纯净的。通过将您的第一个示例放在函数中进行演示:
public static int squareSum(const List<Integer> values)
{
int total = 0;
for(int e : values) {
total += e * 2; // mutates a local variable
}
return total;
}
纯函数式方法甚至不更新局部变量。如果将第二个版本放在函数中,它将是纯的:
public static int squareSum(const List<Integer> values)
{
return values.stream()
.map(e-> e*2)
.reduce(0, (c, e)-> c + e);
}
对于了解其他语言且长期以来更喜欢函数式风格的人来说 map
和 reduce
与 lambda
是很自然的。两个版本都易于阅读和测试,这是最重要的部分。
Java 具有功能 类。 java.lang.String
就是其中之一。
虽然 Royal Bg 是正确的,但您在任何一种情况下都没有改变您的数据,第二个版本没有优势是不正确的。第二个版本可以是高度多线程的,没有歧义。
由于我们不希望迭代列表,我们可以将操作放入大量多线程的上下文中并在 gpu 上解决它。在后者中,集合中的每个数据点都乘以 2。然后减少(这意味着将每个元素加在一起),这可以通过减少来完成。
后一种代码有许多前者所没有的潜在优势。虽然两个代码元素实际上都没有发生变异,但在第二个代码元素中,我们得到了非常明确的约定,即项目 不能 在发生变异时发生变异。所以我们知道我们向前、向后迭代列表或者多线程应用它都没有关系。实现细节可以稍后填写。但是,只有当我们知道突变不会发生并且流根本不允许它们发生时。
为什么第二个代码(带流的那个)比第一个更好?
第一个:
public static void main(String [] args) {
List<Integer> values = Arrays.asList(1,2,3,4,5,6);
int total = 0;
for(int e : values) {
total += e * 2;
}
第二个:
System.out.println(total);
System.out.println(
values.stream()
.map(e-> e*2)
.reduce(0, (c, e)-> c + e));
变异正在改变一个对象的状态,可以是列表,也可以是一些自定义对象。
您的特定代码不会导致列表发生任何变化,因此使用 lambda 代替普通的旧迭代没有实际好处。而且,怪我,但在这种情况下我会使用迭代方法。
有些方法说,每当您需要修改 object/collection 时,您需要 return 使用修改后的数据创建一个新的 object/collection,而不是更改原始数据。这对集合很有用,例如当您同时访问一个集合并且它正在从另一个线程更改时。
当然这可能会导致内存泄漏,因此有一些算法用于管理内存和集合的可变性,即只有更改的节点存储在内存中的另一个位置。
变异正在改变一个对象,是编程语言中的一种常见副作用。
具有功能契约的方法将始终return相同参数的相同值并且没有其他副作用(如存储文件、打印、读取).因此,即使您在函数内部改变临时值,它在外部仍然是纯净的。通过将您的第一个示例放在函数中进行演示:
public static int squareSum(const List<Integer> values)
{
int total = 0;
for(int e : values) {
total += e * 2; // mutates a local variable
}
return total;
}
纯函数式方法甚至不更新局部变量。如果将第二个版本放在函数中,它将是纯的:
public static int squareSum(const List<Integer> values)
{
return values.stream()
.map(e-> e*2)
.reduce(0, (c, e)-> c + e);
}
对于了解其他语言且长期以来更喜欢函数式风格的人来说 map
和 reduce
与 lambda
是很自然的。两个版本都易于阅读和测试,这是最重要的部分。
Java 具有功能 类。 java.lang.String
就是其中之一。
虽然 Royal Bg 是正确的,但您在任何一种情况下都没有改变您的数据,第二个版本没有优势是不正确的。第二个版本可以是高度多线程的,没有歧义。
由于我们不希望迭代列表,我们可以将操作放入大量多线程的上下文中并在 gpu 上解决它。在后者中,集合中的每个数据点都乘以 2。然后减少(这意味着将每个元素加在一起),这可以通过减少来完成。
后一种代码有许多前者所没有的潜在优势。虽然两个代码元素实际上都没有发生变异,但在第二个代码元素中,我们得到了非常明确的约定,即项目 不能 在发生变异时发生变异。所以我们知道我们向前、向后迭代列表或者多线程应用它都没有关系。实现细节可以稍后填写。但是,只有当我们知道突变不会发生并且流根本不允许它们发生时。