Java 7当前Lambda提案的复杂性?(2010年8月)

soc*_*soc 21 java extension-methods closures language-design java-7

有人说每种编程语言都有其"复杂性预算",可用于实现其目的.但是,如果复杂性预算耗尽,每次微小变化都会变得越来越复杂,并且难以以向后兼容的方式实施.

从2010年8月开始阅读Lambda(≙Lambda表达式,异常透明度,防御方法和方法引用)的当前临时语法后,我想知道Oracle在考虑这些更改时是否完全忽略了Java的复杂性预算.

这些是我正在考虑的问题 - 其中一些更多是关于语言设计的:

  • 拟议的新增内容是否与其他语言选择的方法相当?
  • 通常是否可以在语言中添加此类添加内容保护开发人员免受实现的复杂性影响?
  • 这些新增内容是否已经达到了Java-as-a-language演变的终点,或者在改变具有巨大历史的语言时是否会出现这种情况?
  • 在语言演变的这一点上,其他语言采用了完全不同的方法吗?

谢谢!

Dav*_*eas 3

我没有关注Java 7 lambda提案的流程和演变,我什至不确定最新的提案措辞是什么。将此视为咆哮/意见,而不是事实陈述。另外,我已经很久没有使用 Java 了,所以语法可能有些生疏和不正确。

首先,什么是 Java 语言的 lambda?语法糖。虽然一般来说 lambda 允许代码就地创建小型函数对象,但这种支持在某种程度上已经通过使用内部类在 Java 语言中预设了。

那么 lambda 的语法有多好呢?它在哪些方面优于以前的语言结构?哪里可以做得更好?

对于初学者来说,我不喜欢 lambda 函数有两种可用的语法(但这符合 C# 的行,所以我想我的观点并不广泛。我想如果我们想要糖衣,那么 #(int x)(x*x)#(int x){ return x*x; }即使double 语法不会添加任何其他内容。我更喜欢第二种语法,它更通用,但需要额外的编写成本return;简短版本。

为了真正有用,lambda 可以从定义变量的范围和闭包中获取变量。与内部类一致,lambda 仅限于捕获“有效最终”变量。与该语言以前的功能保持一致是一个很好的功能,但为了甜蜜,最好能够捕获可以重新分配的变量。为此,他们正在考虑上下文中存在并用注释的变量将通过引用@Shared捕获,从而允许赋值。对我来说,这似乎很奇怪,因为 lambda 如何使用变量是在变量声明的位置而不是定义 lambda 的位置确定的。单个变量可以在多个 lambda 中使用,这会迫使所有变量具有相同的行为。

Lambda 尝试模拟实际的函数对象,但该提案并没有完全实现:为了保持解析器简单,因为到目前为止,标识符表示一个对象或一个已保持一致的方法,并且调用 lambda 需要!在lambda 名称:#(int x)(x*x)!(5)将返回25. 这为 lambda 带来了一种与该语言的其余部分不同的新语法,它在 某种程度上!代表了虚拟通用接口的同义词,但是,为什么不使其完整呢?.executeLambda<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 );
 }
Run Code Online (Sandbox Code Playgroud)

那么编译器只需要翻译identifier!(args)identifier.exec( args ),就很简单了。lambda 语法的翻译需要编译器识别正在实现的正确接口,并且可以匹配为:

 #( int x )(x *x)
 // translated to
 new Lambda<int,int>{ int exec( int x ) { return x*x; } }
Run Code Online (Sandbox Code Playgroud)

这还允许用户定义在更复杂的情况下可用作 lambda 的内部类。例如,如果 lambda 函数需要捕获以@Shared只读方式注释的变量,或者在捕获位置维护捕获对象的状态,则可以手动实现 Lambda:

 new Lambda<int,int>{ int value = context_value;
     int exec( int x ) { return x * context_value; }
 };
Run Code Online (Sandbox Code Playgroud)

其方式与当前内部类定义类似,因此对于当前 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.
Run Code Online (Sandbox Code Playgroud)

这将允许使用 lambda 和接受 lambda 的方法,既可以使用新的简单语法,#(int x){ return x*x; }也可以使用更复杂的手动方法来处理糖衣干扰预期语义的特定情况。

总的来说,我相信 lambda 提案可以在不同的方向上进行改进,它添加语法糖的方式是一种泄漏抽象(您已经在外部处理了 lambda 特有的问题),并且通过不提供较低级别的接口,它可以在不完全适合简单用例的用例中,使用户代码的可读性较差。: