说明
每个只提供一个(抽象)方法的接口,即没有实现的接口,都是所谓的功能接口。
无论是明确的还是隐含的。
注解@FunctionalInterface 和@Override 一样,是可选的,如果你想创建一个功能接口。
所以如果你声明了一个接口@FunctionalInterface,但它实际上不止一个这样的方法,编译器会帮助你并防止编译出错。告诉你你违背了自己的意图。
如果你没有注解,它会编译,但它不再是一个功能接口。这对您来说可能是一个错误,因为您的意图是创建一个功能界面。请注意,如果您实际上是在实际需要函数式接口的环境中使用该接口,例如对于 lambda,那么一旦将另一个方法添加到接口中,它显然就不会再编译了。
这里有一些例子:
// is a functional interface
interface Foo {
void bar();
}
// is a functional interface
@FunctionalInterface
interface Foo {
void bar();
}
// is not a functional interface
interface Foo {
void bar();
void baz();
}
// does not compile
@FunctionalInterface
interface Foo {
void bar();
void baz();
}
使用
这是为了让编译器、其他团队成员和你未来的自己清楚你的意图。这样,编译器可以帮助您发现错误,以防万一您搞砸了。
如果您在团队中工作并设计界面,则可能是另一种情况。如果您没有通过注释或注释/文档明确将此接口标记为功能接口,则其他团队成员可能不知道您的意图并为其添加更多方法。
如果您是库设计师,即编写供其他外部人员使用的代码,这一点尤其重要。如果你标记你的界面@FunctionalInterface,这是对他们的承诺,你打算保持这种状态。例如,他们可以安全地将其用于 lambda。不用担心他们的代码会在您向您的库发布更新后立即中断。
相反的情况也是如此。如果他们发现您的接口只有一个方法,但没有明确注释,他们会明白这并不意味着用作功能接口,即使它目前是一个。因此,他们不会将它用于 lambda,尽管他们可以,因为您可能会在未来的更新中更改它。
详情
您可以阅读JLS§9.8. Functional Interfaces中的精确定义:
函数式接口是一个只有一个抽象方法(除了 Object 的方法)的接口,因此代表一个单一的函数契约。这种“单一”方法可以采用多个抽象方法的形式,这些方法具有从超接口继承的重写等效签名;在这种情况下,继承的方法在逻辑上代表一个方法。
还有JLS§9.6.4.9. @FunctionalInterface:
注解类型FunctionalInterface 用于指示接口是功能接口(第9.8 节)。它有助于及早发现出现在本应具有功能的接口中或由其继承的不适当方法声明。
如果接口声明使用@FunctionalInterface 注释但实际上不是函数式接口,则会出现编译时错误。
由于某些接口是函数式的,因此没有必要或不希望所有函数式接口的声明都使用@FunctionalInterface 进行注释。
这里的最后一段尤其重要。 IE。您可能偶然创建了一个功能接口,并计划稍后添加更多功能。所以人们不应该把它与 lambdas 一起使用,否则当你添加更多方法时,他们的代码会中断。
注意
如前所述,@Override 标记的工作方式相同,但用于覆盖方法。因此,您也可以在没有它的情况下覆盖方法。但是如果你使用它并且可能打错了,即你实际上并没有覆盖某些东西,编译器会帮助你立即发现这个问题。