比较C#和Java中的lambda捕获

时间:2017-02-04 15:11:30

标签: java c# lambda

提供C#代码:

int x = 10;

Func<int> next = () => { return ++x; };

Console.WriteLine("Before lambda, x = {0}", x);
Console.WriteLine("The successor of {0} is {1}", x, next());
Console.WriteLine("After lambda,  x = {0} \n", x);

输出结果为:

Before lambda, x = 10
The successor of 10 is 11
After lambda,  x = 11

在lambda之后,x的值受lambda动作的影响,所以这相当于通过引用将参数传递给函数。

让我们与Java比较:

interface Inc
{
    int Increment();
}

int x = 10;
Inc next = () -> { return ++x; };

System.out.println("Before lambda, x = " + x);
System.out.println("The successor of " + x + " is " + next.Increment()); // ERROR: local variables referenced from a lambda expression must be final or effectively final
System.out.println("After lambda,  x = " + x + "\n");

如果我将lambda更改为:

Inc next = () -> { return x+1; };

输出结果为:

Before lambda, x = 10
The successor of 10 is 11
After lambda,  x = 10

在lambda之后,x的值不受lambda动作的影响,因此,这相当于通过值将参数传递给函数。

阻止Java更改捕获的变量的技术原因是什么?

我知道错误信息的内容:

«从lambda表达式引用的局部变量必须是最终的或有效的最终版<»em>

但这对我来说还不够。这背后的技术原因是什么?

如果Java允许lambda更改捕获的变量会有什么后果?

谢谢。

1 个答案:

答案 0 :(得分:0)

Java和JVM不支持对局部变量的引用。编译器可以做的是将变量转换为引用,但它没有。

e.g。它可以像这样翻译你的代码。

int[] x = { 10 };
IntSupplier next = () -> { return ++x[0]; };

System.out.println("Before lambda, x = " + x);
System.out.println("The successor of " + x + " is " + next.getAsInt()); // 
System.out.println("After lambda,  x = " + x + "\n");

如果你真的需要这个,你可以自己更改代码。

BTW函数式编程的一个关键特性是尽可能使用纯函数。纯功能没有副作用。虽然Java没有任何方法可以强制执行纯函数,但是iMHO似乎添加一种方法来产生微妙的副作用并不会与添加功能结构保持一致。