Java 8中的类型推断


30

Java 8中新的lambda表示法的引入(请参阅例如本文)是否需要某种类型推断?

如果是这样,新型系统将如何对整个Java语言产生影响?

Answers:


47

棘轮怪胎的答案及其注释线程中存在相当多的错误信息。由于评论太小,我将在此处回答。另外,由于毕竟这是一个答案,所以我也将尝试回答原始问题。(但是请注意,我不是类型系统方面的专家。)

首先,对原始问题的简短回答是“是”和“否”。是的,Java 8的类型推断要比Java 7大得多,并且,不,Java 8中没有“新”类型系统,尽管有一些细微的变化。

Java 8仍将是静态类型的,并且在类和接口之间仍然存在二分法。没有新类型,例如函数类型。Lambda的类型实质上是“功能接口”,它是具有单个抽象方法的普通接口。

接口现在可以具有默认方法形式的代码,但是类的单继承和接口的多重继承的模型保持不变。当然,有一些调整,例如在存在默认方法的情况下用于方法解析的规则,但是基本原理没有变化。

通过类型推断推断出的任何类型都可以显式地写出。以棘轮怪胎为例,

Collections.<MyClass>sort(list, (a, b) -> { return a.order - b.order; });

基本上是糖

Collections.<MyClass>sort(list,
    (Comparator<MyClass>)((MyClass a, MyClass b) -> { return a.order - b.order; }));

因此,sparkleshy的“类型推断不需要任何类型系统扩展”的说法基本上是正确的。

但是要回到语法糖上,我将重复我的声明:对于匿名内部类lambda表达式不是语法糖。Ratchet freak声明将lambda表达式转换为匿名内部类实例化,Sparkleshy只是简单地断言lambda 匿名内部类的语法糖,但是这些语句是错误的。它们可能基于过时的信息。早期的lambda实现确实以这种方式实现了lambda,但是情况已经发生了变化。

Lambda表达式在语义上与内部类不同,并且在实现方式上与内部类不同。

Lambda表达式在语义上与内部类有所不同。评估lambda表达式不必每次都创建一个新实例。他们也有不同的捕获语义,例如,他们抓住这个不同。在内部类中,是内部类实例,而在lambda中,是封闭实例。考虑以下:

public class CaptureThis {
    void a(Runnable r) { r.run(); }

    void b() {
        a(new Runnable() { public void run() { System.out.println(this); }});
        a(() -> System.out.println(this));
    }

    public String toString() { return "outer"; }

    public static void main(String[] args) { new CaptureThis().b(); }
}

在最近的JDK 8 lambda构建(我使用b69)中,输出将类似于以下内容:

CaptureThis$1@113de03
outer

此外,lambda表达式的实现与内部类完全不同。如果比较反汇编的输出,您会看到内部类代码直接编译为创建并调用CaptureThis $ 1的构造函数,而lambda表达式编译为invokedynamic指令,该指令通过未指定的方式获取Runnable。有关其工作原理和原因的完整说明,请参见Brian Goetz在JavaOne 2012上发表的演讲Lambda:深入了解


2
“他们不同的捕捉这在一个内部类,这是内部类的实例,而在拉姆达,这是封闭的情况下考虑以下几点:”还可以用语法糖通过更换全部完成thisMyClass.this
棘轮怪胎

4
超出汇编程序(有时甚至包括汇编语言)的所有东西都可以说是语法糖。但是lambda 不再是内部类的语法糖。它们的目标相似,并且有一些相似之处,但在幕后,它们是(显而易见的)不同。
约阿希姆·绍尔

1
“ Lambda表达式在语义上与内部类不同,它们的实现与内部类也不同。”:感谢您的出色解释(+1)。我仍然不清楚的是,为什么 lambda没有被实现为特殊匿名类的语法糖,或者换句话说,新语义引入的额外复杂性有什么好处?匿名内部类无法解决什么问题?(但我仍然必须查看您发布的链接,也许我会在那找到答案。)
Giorgio 2013年

1
@Joachim Sauer:我认为语法糖是现有语义的新语法。当引入新的语义时,我认为您不能谈论语法糖。从这个意义上讲,我认为您不能认为汇编程序之外的所有东西都是语法糖。
Giorgio 2013年

3
@Giorgio:关于为什么lambda不仅仅是匿名内部类的语法糖,事实证明,对此进行了大量讨论。Brian Goetz的这封邮件总结了这一决定:mail.openjdk.java.net/pipermail/lambda-dev/2011-August/…。TL; DR为未来的发展敞开了大门,今天我们获得了更好的性能。Goetz实际上在回答一个相关的问题:lambdas对象吗?但是,如果答案是“否”甚至“也许”,则意味着它们不能成为内部阶级的糖。
Stuart Marks
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.