Lambda表达式除了具有单个方法的匿名内部类之外,还具有其他功能吗?


40

期待已久的Java 8中的lambda表达式有了新的炒作;每三天有一篇关于他们有多酷的文章随他们出现。

据我了解,lambda表达式只不过是具有单个方法的匿名内部类(至少在字节码级别)。除此之外,它还具有另一个不错的功能-类型推断,但我相信可以在某种程度上使用泛型来实现这一点(当然不能像使用lambda表达式那样巧妙)。

知道了这一点,lambda表达式不仅会带来Java语法上的加糖功能吗?是否可以使用无法使用当前语言功能构建的lambda表达式来创建功能更强大,更灵活的类或其他面向对象的构造?


30
当一种语言完成巡回演出时,理论上每个附加功能都可以描述为“语法糖”。
菲利普

34
@Philipp:错了。语法糖的定义特征是,糖精纯纯是局部的,不会改变程序的全局结构。有很多功能不能仅通过局部转换来实现。例如,如果您采用一种与Java相同的假设语言,但具有正确的尾部调用,则在不全局转换整个程序的情况下就不可能将尾部调用糖化为“纯” Java。
约尔格W¯¯米塔格

2
@Philipp:不幸的是,只有一个投票赞成评论,否则我会投票赞成Joerg的评论1000次。不,任何功能都可以描述为语法糖是错误的。语法糖不会添加新的语义。实际上,AFAIK提出的Java lambda并不是特殊匿名内部类的语法糖,因为它们具有不同的语义。
Giorgio

1
@乔治:它们有什么不同的语义?
user102008

2
@Giorgio:是的,但转化thisOuterClass.this是脱糖lambda表达式为匿名类过程的一部分。
user102008 2013年

Answers:


47

tl; dr:虽然它主要是语法糖,但是更好的语法使许多事情变得实用,这些事情过去常常以无休止的花括号和括号结尾。

那么,它实际上是围绕为lambda表达式是其他的方式很多比Java更旧。具有单个方法的匿名内部类是(最接近)lambdas的Java。这种近似在一段时间内“足够好”,但是语法非常讨厌。

从表面上看,Java 8 lambda似乎不过是语法糖,但是当您从表面看时,会看到大量有趣的抽象。例如,JVM规范对lambda的处理与“ true”对象的处理有很大不同,尽管您可以将它们当作对象所在的对象来处理,但JVM并不需要照此实现。

但是,尽管所有这些技术技巧都是有趣且相关的(因为它允许将来在JVM中进行优化!),但真正的好处是“只是”语法糖部分。

什么更容易阅读:

myCollection.map(new Mapper<String,String>() {
  public String map(String input) {
    return new StringBuilder(input).reverse().toString();
  }
});

要么:

myCollection.map(element -> new StringBuilder(element).reverse().toString());

或(使用方法句柄而不是lambda):

myCollection.map(String::toUpperCase);

您可以在一个简洁的方式将其以前是5行代码,终于表明了一个事实(这3完全无聊的)带来了什么是真正的变化实际(但不是什么是可能的,授予)。


1
我完全同意语法加糖部分。我的问题是关于只有lambda表达式才有可能的新的面向对象的构造。毕竟Java是一种面向对象的语言。与泛型进行比较,想想它们如何在Java中获得很大的灵活性,而没有它们,灵活性是无法实现的。
m3th0dman

7
@ m3th0dman:实际上泛型没有添加任何新功能。一个List可以容纳任何对象,一个List<String>可以“仅”容纳字符串。泛型添加了一个限制(以及可以将限制形式化的选项!),而不是功能上的增加。自Java 1.1以来,几乎所有东西都是语法糖。那不一定是一件坏事。
Joachim Sauer

3
@ m3th0dman:实际上,泛型没有添加任何新功能,因为在Java中它们只是语法糖。A List<String>只是一个List带有强制转换的A ,String并在一些返回值周围添加了A。但是,它们非常有用,并使编写语言更加方便。Lambda与之类似。
Jan Hudec

3
实际上,它不仅仅是语法糖。通过使用invokedynamic字节码+类型推断系统的一些相当大的改进,许多功能在JVM中被实现为一等公民。它没有实现为匿名内部类。
Martijn Verburg

1
@JanHudec:好吧,它们比语法糖稍微多一点,因为编译器实际上尊重它们。在运行时并不关心他们,这是事实。
Joachim Sauer

14

对于Java,是的,无非就是创建匿名内部类的更好方法。这是由于Java中的基本决定,即字节代码的每一位都必须存在于特定的类中,经过数十年的遗留代码考虑,现在无法更改。

但是,这并不是lambda表达式真正的目的。在形式主义中,lambda是本机概念,而不是一时流行的扭曲,它是基本的构建块;他们的语法和人们对他们的态度都大不相同。纯粹根据计算机程序的结构和解释中的lambda创建的匿名递归函数示例可以更改您的整个计算概念。(但是,我可以肯定的是,学习编程的方法只是深奥的成为主流成功的故事。)


1
在我看来,了解所有可以使用lambda实现的方法都是很有启发性的,而不是“深奥的”。(但是,我想大多数“编码器”都不关心有趣的CS理论。)这并不意味着lambda很特别;它只是意味着lambda是一种通用构造。还有其他一些,例如SKI组合器。Lambda是功能范式中的基本构建块,但在其他范式中,可能还有其他基本内容。
user102008

+1代表“赶时髦的扭曲”:我经常想知道为什么某些语言会不断变化以模仿其他流行语言,以及程序员为什么会忍受它。我喜欢lambda,并且在Scala,Lisp,Haskell中经常使用lambda,但是在Java或C ++中,它们感觉就像是事后的想法,只是因为它们已在其他语言中流行。
Giorgio 2016年

2

是的,它只是语法上的糖,在某种意义上,您编写lambda的任何地方都可以使用一种方法将该表达式重新编写为匿名内部类表达式,其中该类实现针对lambda上下文推断的功能接口,并且它在语义上完全等效。您可以通过简单地将lambda表达式替换为匿名类表达式来完成此操作,而无需更改任何其他表达式或代码行。


1
为什么要投票?我所说的完全正确
user102008

您写的内容对于Java lambda来说似乎是一个合理的建议,但是为了另一个建议而放弃了该建议(doanduyhai.wordpress.com/2012/07/12/…)。
Giorgio

1
@乔治:我不是在“提议”任何东西。确切地说,您不同意我说的话吗?是的,表达式的内部看起来会有所不同,例如,我们将添加一个方法,并且this需要将其转换为OuterClass.this。这与我所说的并不矛盾-每个lambda 表达式都可以转换成语义上等效的匿名类表达式,而无需更改该表达式之外的任何内容。我并不是说内部不会改变。
user102008 2013年

3
你说的不对。lambda和anon内部类的语义并不完全相同(尽管它们是相似的)。把我的头,的意思意思顶部变化; 内部匿名类总是导致对象的新实例,而lambda可能会或可能不会。
Stuart Marks 2013年

1
@StuartMarks:不,您没有阅读我的答案。我并不是说他们每个人都能做其他的事情。我说过,lambda具有等效的匿名类,在语义上是相同的。正如我在评论中已经说过的那样,thislambda是语法糖的一部分,并且在语义上没有区别。关于实现方面的差异,实现!=语义。关于对象身份的差异;对象标识与lambda的功能极为相切;没人会检查lambdas / anon类的对象标识,因为它没有用。
user102008 2013年

1

约阿希姆·绍尔(Joachim Sauer)在回答您的问题上做得很好,但仅暗示了我认为重要的事情。由于Lambda不是类,因此它们也不会这样编译。所有匿名内部类都会创建一个.class文件,而该文件又必须由ClassLoader加载。因此,使用Lambdas不仅可以使您的代码更加美观,还可以减少编译后代码的大小,ClassLoader的内存占用以及从硬盘驱动器传输位的时间。


-1

不,他们不是。

另一种表达方式是lambda是一种非面向对象的方法,无论它是多么简洁,都可以实现与匿名类或我的首选内部类将以面向对象的方式实现的目标相同的东西。


1
函数式编程可以与面向对象的编程完全正交(请参阅:Scala和F#)。这听起来像是有些人根本不喜欢函数式编程的观点。
KChaloux 2014年

1
@KChaloux-不是函数编程的讨厌人。答案是由喜欢用锤子和螺丝刀而不是锤子的人写的。OO编程和函数式编程一样,是一个很好的范例。我更喜欢一种语言,是因为它应该清楚其意图。Lambdas我感到Java否则具有OO的本质就变得混乱。Java并非被设计为一种功能语言。人类需要结构来尽力而为。
Guido Anselmi 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.