Java 8为我们提供了许多有趣的方法来使用功能界面,并为它们添加了一个新的注释:@FunctionalInterface。如果我们不遵守功能接口的规则(只需要一个需要覆盖的抽象方法),它的工作就是告诉编译器对我们大喊大叫。
此注释有43 interfaces in the java.util.function package个。搜索@FunctionalInterface
的jdk.1.8.0 / src只能获得57次点击。为什么可能添加@FunctionalInterface
的其他接口(例如AutoCloseable)仍然缺少它?
annotations documentation中有一点含糊的暗示:
"信息性注释类型,用于指示界面类型声明意图是一个功能界面"
有没有什么好理由不打算我设计的界面(可能只是一个功能界面)不能用作一个界面?除了没有意识到它可以被添加之外,是否有任何迹象?
是否不会将抽象方法添加到任何已发布的界面,以阻止任何人实现它,功能与否?我觉得他们只是没有费心去追捕他们,但是还有其他解释,我感到愤世嫉俗?
更新:在查看"Should 'Comparable' be a 'Functional interface'?"后,我发现我仍然有唠叨的问题。当单一方法接口和功能接口在结构上相同时,它们会有什么不同?简单的名称是不同的? Comparable和Comparator在语义上足够接近。事实证明它们在结构上是不同的,但仍然不是最好的例子......
是否存在SMI在结构上很好用作功能接口但仍然不鼓励接口名称和方法的语义含义的情况?或者也许是Javadocs隐含的合同?
答案 0 :(得分:20)
好吧,如果你假设总是有这样的意图,那么记录意图的注释将毫无用处。
您将示例AutoCloseable
命名为 not ,意图将其作为函数实现,因为Runnable
对于具有{{1的函数来说更方便签名。它旨在实现()->void
的类管理外部资源,通过lambda表达式实现的匿名类不会这样做。
一个更清晰的例子是AutoCloseable
,Comparable
不仅不打算作为lambda表达式实现,也不可能使用lambda表达式正确实现它。
interface
interface
的可能原因:@FunctionalInterface
具有编程语言语义,例如interface
或AutoClosable
(这不太可能发生在您自己的界面上)Iterable
不具有任意实现和/或不是实际实现的标识符,例如interface
或java.net.ProtocolFamily
(请注意,后者也会继承java.lang.reflect.GenericArrayType
default
实现,因为getTypeName()
依赖于toString()
此interface
的实例应具有标识,例如java.net.ProtocolFamily
,java.nio.file.WatchEvent.Modifier
等。请注意,这些通常由enum
另一个示例是java.time.chrono.Era
恰好只有一个abstract
方法,但its specification表示可以使用Era
运算符比较==
的实例。”
interface
旨在改变interface
的实现而不继承/实现其他任何内容的操作的行为,例如, java.rmi.server.Unreferenced
java.io.Closeable
,java.io.Flushable
,java.lang.Readable
java.awt
:ActiveEvent
应该由AWTEvent
,PrinterGraphics
由Graphics
实施,同样适用于java.awt.print.PrinterGraphics
(嘿,两个{ {1}}对于完全相同的事情...),interface
应该由javax.print.FlavorException
子类实现javax.print.PrintException
标记与其他多方法事件监听器的对称性,这些监听器不能是功能接口,但实际上事件监听器是lambda的良好候选者表达式。如果你想在以后删除一个监听器,你必须存储实例,但这与实例没有区别,例如内部类监听器实现。库维护者拥有一个包含200多种候选类型的大型代码库,而不是每个@FunctionalInterface
讨论的资源是否应该注释,因此专注于在功能中使用的主要候选者上下文。我敢肯定,例如, interface
,java.io.ObjectInputValidation
,juc java.lang.reflect.InvocationHandler
& RejectedExecutionHandler
不会像ThreadFactory
那样糟糕,但我不知道是否,例如@FunctionalInterface
是一个很好的候选人。图书馆越普遍,图书馆的用户就越有可能为他们感兴趣的特定java.security.spec.ECField
回答这个问题,但坚持图书馆维护人员为所有接口。
在这种情况下,更有意义的是将interface
视为一条消息,@FunctionalInterface
绝对可以与lambda表达式一起使用,而不是将注释的缺失视为它的指示器不打算以这种方式使用。这与编译器处理它完全一样,您可以使用lambda表达式实现每个抽象方法interface
,但是当注释出现时,它将确保您可以使用此{{1以这种方式。
答案 1 :(得分:2)
计划扩展。仅仅因为接口符合SMI的要求现在并不意味着以后不需要扩展。
答案 2 :(得分:0)
在java 8中,函数接口是一个接口,它只有一个称为函数方法的抽象方法,lambda表达式的参数和返回类型匹配。
java.util.function
包含JDK使用的通用功能接口,也可供最终用户使用。虽然它们不是lambda表达式可能适用的完整的功能接口集,但它们提供了足以满足常见要求的功能。只要现有的设置不够,您就可以自由创建自己的功能接口。
有许多这样的接口值得指定为功能接口,但java.util.function
包已经为我们几乎所有目的提供了功能接口。
例如,请查看以下代码。
public interface Comparable<T> {
public int compareTo(T o);
}
@FunctionalInterface
public interface ToIntFunction<T> {
int applyAsInt(T value);
}
public static void main(String[] args){
ToIntFunction<String> f = str -> Integer.parseInt(str);
Comparable<String> c = str -> Integer.parseInt(str);
}
Comparable
也可以获取一个对象并派生一些int类型值,但是提供了一个更通用的专用接口ToIntFunction
来执行此任务。 没有这样的硬性规则,所有值得使用@FunctionalInterface
注释,但为了获得lambda特性的优势,接口应该满足FunctionalInterface定义的所有标准。