26

函数式接口的定义是“函数式接口是只有一个抽象方法(除了 Object 的方法)的接口,因此代表一个单一的函数契约。”

根据这个定义,Comparable<T>绝对是一个函数式接口。

lambda 表达式的定义是“一个 lambda 表达式就像一个方法:它提供了一个形式参数列表和一个主体 - 一个表达式或块 - 用这些参数表示。”

对 lambda 表达式的求值会生成一个功能接口的实例。

因此,lambda 表达式的目的是能够通过实现功能接口的单个​​函数来创建功能接口的实例。IE。允许使用单个函数创建实例。

让我们看一下Comparable<T>,这个界面是为单一功能设计的吗?IE。它是为创建仅具有此单个功能的实例而设计的吗?

的文档Comparable<T>以“此接口对实现它的每个类的对象施加总排序。这种排序称为类的自然排序,类的 compareTo 方法称为其自然比较方法。”

上面这句话清楚地表明,Comparable<T>它并非旨在用作单个函数,而是始终由一个类实现,该类通过添加这个单个函数对其实例具有自然顺序。

这意味着它不是设计为使用 lambda 表达式创建的?

关键是我们不会有任何只是 Comparable 的对象,它旨在被实现并因此用作类的附加功能。

那么,Java 语言中有没有一种方法Comparable<T>可以防止创建 lambda 表达式?接口的设计者是否可以决定该接口是由一个类实现的,而不是通过使用 lambda 表达式使用这个单一方法创建为实例的?

仅仅因为一个接口碰巧有一个抽象方法,它不应该被认为是一个功能接口。

也许,如果 Java 提供了 NotFunctional 之类的注解,编译器可以检查该接口不用于创建 lambda 表达式,例如。

@NotFunctional
public interface Comparable<T> { public int compareTo(T t); }
4

4 回答 4

28

当需要具有单个抽象方法的接口实例时,可以使用 lambda 表达式。你写了,

仅仅因为一个接口碰巧有一个抽象方法,它不应该被认为是一个功能接口。

这是完全正确的。拥有一个抽象方法是接口的一种结构属性,它使它有资格用 lambda 实现。但是,使用 lambda 实现接口是否有意义语义是否合理则是另一回事。后者是@FunctionalInterface注释的目的。当它出现在接口上时,它表明该接口对于使用lambda实现是有用的。

值得注意的是,Comparable界面缺少@FunctionalInterface注释。

虽然使用 lambda 作为Comparable实现可能是荒谬的,但似乎没有任何理由创建一种机制来防止这种情况发生。这样做似乎不会成为错误的来源,这将是开发这种机制的一个很好的理由。相比之下,@FunctionalInterface注释旨在引导程序员朝着正确的方向前进,而不是禁止一些可以说是错误但似乎并不真正有害的事情。

于 2014-08-10T00:50:28.200 回答
8

问题来自“方法”和“函数”之间的细微差别。

函数的输出值仅取决于输入到该函数的参数。

然而,方法的输出取决于输入到函数的参数,但它也可能取决于对象的状态(实例变量)。

也就是说,任何函数都是方法,但并非所有方法都是函数。

例如,接口 Comparator 中的方法 compare 仅取决于其参数。但是,Comparable 接口中的 compareTo 方法依赖于要比较的对象的状态,因此需要在类中实现。

因此,即使 Comparable 也有一个抽象方法,从语义上讲,它不应该被视为功能接口。

于 2015-04-17T11:46:03.210 回答
2

好吧,除了讨论信息性注释@FunctionalInterface的有用性之外(我很高兴 Java 8 不需要它用于 lambda)。

Comparable通常是类型的属性,因此不适合作为功能接口。它被明确描述为自然排序,并且不采用两个 this/that 参数。所以这个属性使得任何方法都不太可能在 lambda 上运行(类似的参数适用于几乎所有-able接口)。

因此,集合设计者为该任务使用了第二个接口:Comparator<T>,为此,实现它的 lambda 是一个非常自然的选择。

于 2014-08-10T01:12:19.490 回答
0

没有机制可以防止对不打算成为功能接口的接口进行天真使用。通过像@NotFunctional 这样的附加注释,它可以由接口的设计者显式声明,它不应该用作 lambda。而且默认如果没有指定注解,也可以认为和@Functional一样好,目前就是这样。

于 2014-08-11T09:21:00.203 回答