抽象类作为功能接口

在java 8中,只有一个抽象方法的抽象类不是函数接口(JSR 335)。

这是一个功能接口:interface

public interface MyFunctionalInterface {
    public abstract void myAbstractMethod();
    public default void method() {
        myAbstractMethod();
    }
}

但这不是:abstract class

public abstract class MyFunctionalAbstractClass {
    public abstract void myAbstractMethod();
    public void method() {
        myAbstractMethod();
    }
}

所以我不能使用抽象类作为lambda表达式和方法引用的目标。

public class Lambdas {
    public static void main(String[] args) {
        MyFunctionalAbstractClass functionalAbstractClass = () -> {};
    }
}

编译错误为:。The target type of this expression must be a functional interface

为什么语言设计者施加了这个限制?


答案 1

自Lambda项目启动以来,这一直是一个重要的话题,并且已经收到了很多思考。首席Java语言架构师Brian Goetz强烈支持将lambda视为一个函数,而不是一个对象。报价:

我相信,发展Java的最佳方向是鼓励一种更实用的编程风格。Lambda 的作用主要是支持更多类似功能的库的开发和使用。

我对Java的未来持乐观态度,但为了向前迈进,我们有时不得不放弃一些舒适的想法。Lambdas-are-functions打开了大门。Lambdas-are-objects 会关闭它们。我们宁愿看到这些门敞开。

以下是引用来源的链接,这是Brian最近的帖子,它重申了相同的哲学观点,并通过其他更实用的论点重申了它们:

使模型更简单为各种 VM 优化打开了大门。(抛弃身份是这里的关键。函数是值。将它们建模为对象会使它们比需要的更重,更复杂。

在将此用例放在总线下之前,我们进行了一些语料库分析,以发现与接口 SAM 相比,抽象类 SAM 的使用频率。我们发现,在该语料库中,只有 3% 的 lambda 候选内部类实例将抽象类作为其目标。他们中的大多数都适合简单的重构,其中你添加了一个构造函数/工厂,接受一个面向接口的lambda。


答案 2