我没有关注 Java 7 lambda 提案的过程和演变,我什至不确定最新的提案措辞是什么。将此视为咆哮/意见,而不是事实陈述。此外,我已经很久没有使用 Java,所以语法可能在某些地方生锈和不正确。
首先,什么是 Java 语言的 lambda?语法糖。虽然通常 lambdas 使代码能够在适当的位置创建小型函数对象,但这种支持已经在 Java 语言中通过使用内部类预先设置——在某种程度上。
那么 lambda 的语法有多好呢?它在哪些方面优于以前的语言结构?哪里可以更好?
对于初学者来说,我不喜欢 lambda 函数有两种可用语法这一事实(但这属于 C# 行,所以我想我的观点并不普遍。我想如果我们想粉饰一下,那么
#(int x)(x*x)
比#(int x){ return x*x; }
即使双重语法没有添加任何其他东西。我更喜欢第二种语法,更通用,但需要额外的写作成本return
和
;
短版本。
为了真正有用,lambda 可以从定义它们的范围和闭包中获取变量。与内部类一致,lambda 仅限于捕获“有效最终”变量。与该语言以前的特性保持一致是一个很好的特性,但是为了甜蜜,能够捕获可以重新分配的变量会很好。为此,他们正在考虑将通过引用@Shared
捕获上下文中存在并带有注释的变量,允许分配。对我来说,这似乎很奇怪,因为 lambda 如何使用变量是在声明变量的位置而不是定义 lambda 的位置确定的。一个变量可以在多个 lambda 中使用,这会在所有 lambda 中强制执行相同的行为。
Lambda 试图模拟实际的函数对象,但该提议并未完全实现:为了保持解析器简单,因为到目前为止,标识符表示对象或方法已保持一致,并且调用 lambda 需要!
在lambda 名称:#(int x)(x*x)!(5)
将返回25
. 这带来了一种用于 lambda 的新语法,该语法不同于其他语言,其中
以!
某种方式作为.execute
虚拟通用接口的同义词,Lambda<Result,Args...>
但是,为什么不让它完整呢?
Lambda
可以创建一个新的通用(虚拟)接口。它必须是虚拟的,因为接口不是真正的接口,而是这样的系列:Lambda<Return>
, Lambda<Return,Arg1>
,
Lambda<Return,Arg1,Arg2>
... 他们可以定义一个执行方法,我希望它像 C++ 一样operator()
,但如果这是一个负担,那么任何其他名称都可以,将其!
作为方法执行的快捷方式:
interface Lambda<R> {
R exec();
}
interface Lambda<R,A> {
R exec( A a );
}
然后编译器只需要翻译identifier!(args)
成
identifier.exec( args )
,这很简单。lambda 语法的翻译需要编译器识别正在实现的正确接口,并且可以匹配为:
#( int x )(x *x)
// translated to
new Lambda<int,int>{ int exec( int x ) { return x*x; } }
这也将允许用户在更复杂的情况下定义可用作 lambdas 的内部类。例如,如果 lambda 函数需要以@Shared
只读方式捕获带注释的变量,或在捕获位置维护捕获对象的状态,则可以使用 Lambda 的手动实现:
new Lambda<int,int>{ int value = context_value;
int exec( int x ) { return x * context_value; }
};
以类似于当前内部类定义的方式,因此对当前 Java 用户来说是自然的。例如,这可以在循环中用于生成乘数 lambda:
Lambda<int,int> array[10] = new Lambda<int,int>[10]();
for (int i = 0; i < 10; ++i ) {
array[i] = new Lambda<int,int>{ final int multiplier = i;
int exec( int x ) { return x * multiplier; }
};
}
// note this is disallowed in the current proposal, as `i` is
// not effectively final and as such cannot be 'captured'. Also
// if `i` was marked @Shared, then all the lambdas would share
// the same `i` as the loop and thus would produce the same
// result: multiply by 10 --probably quite unexpectedly.
//
// I am aware that this can be rewritten as:
// for (int ii = 0; ii < 10; ++ii ) { final int i = ii; ...
//
// but that is not simplifying the system, just pushing the
// complexity outside of the lambda.
这将允许使用新的简单语法的 lambda 和接受 lambda 的方法:#(int x){ return x*x; }
或者在糖衣干扰预期语义的特定情况下使用更复杂的手动方法。
总的来说,我相信 lambda 提案可以在不同的方向进行改进,它添加语法糖的方式是一种泄漏抽象(您已经在外部处理了 lambda 特有的问题),并且不提供较低级别的接口它在不完全适合简单用例的用例中,使用户代码的可读性降低。: