为什么不在 JDK 中所有符合条件的接口上使用@FunctionalInterface?

Java 8为我们提供了许多使用功能接口的有趣方式,并带有一个新的注释:@FunctionalInterface。它的工作是告诉编译器,如果我们没有遵守功能接口的规则,就对我们大喊大叫(只有一个抽象的方法需要覆盖)。

java.util.function 包中有 43 个接口具有此注释。在 jdk.1.8.0/src 上搜索只找到 57 次点击。为什么本来可以添加的其他接口(如自动关闭)仍然缺少它?@FunctionalInterface@FunctionalInterface

注释文档中有一些模糊的提示:

“一种信息性注释类型,用于指示接口类型声明旨在成为功能接口”

有什么好的理由不打算将我设计的界面(可能只是碰巧是一个功能性界面)不用作一个接口吗?除了没有意识到它可以被添加之外,把它排除在外,这是否表明任何事情?

将抽象方法添加到任何已发布的接口中,难道不会让任何实现它的人(无论功能正常与否)搞砸吗?我感到愤世嫉俗,假设他们只是懒得追捕他们,但还有什么其他的解释呢?

更新:在查看了“'可比较'应该是'功能界面'吗?我发现我仍然有唠叨的问题。当单方法接口和功能接口在结构上相同时,还有什么不同之处?区别仅仅是名字吗?可比和比较器在语义上足够接近相同。事实证明,它们在结构上是不同的,所以仍然不是最好的例子......

是否存在这样的情况:SMI 在结构上可以用作功能接口,但仍然不鼓励使用接口名称和方法的语义含义?或者也许是Javadocs暗示的合同?


答案 1

好吧,如果你假设总是有这个意图,那么记录一个意图的注释将是无用的。

您命名的示例显然不打算作为函数实现,因为对于具有签名的函数来说,这更方便。它的目的是让实现的类管理外部资源,而通过 lambda 表达式实现的匿名类不会这样做。AutoCloseableRunnable()->voidAutoCloseable

一个更清晰的例子是,不仅不打算作为lambda表达式实现,而且使用lambda表达式正确实现它是不可能的。Comparableinterface


不用标记的可能原因示例:interface@FunctionalInterface

  • 具有编程语言语义,例如 或者(对于您自己的接口,这不太可能发生)interfaceAutoClosableIterable
  • 预计 没有期望具有任意实现和/或比实际实现更多的标识符,例如,或(请注意,后者也会继承一个实现,因为对于lambda实现无用,因为依赖于interfacejava.net.ProtocolFamilyjava.lang.reflect.GenericArrayTypedefaultgetTypeName()toString())
  • 这种情况的实例应具有标识,例如 、 等。请注意,这些通常由interfacejava.net.ProtocolFamilyjava.nio.file.WatchEvent.Modifierenum

    另一个例子是碰巧只有一个方法,但它的规范说“可以使用运算符比较的实例”。java.time.chrono.EraabstractEra==

  • 旨在改变一个操作的行为,对于该操作,在没有继承/实现任何其他内容的情况下实现没有意义,例如interfaceinterfacejava.rmi.server.Unreferenced
  • 它是类的常见操作的抽象,这些类应该不仅仅是这些操作,例如,,java.io.Closeablejava.io.Flushablejava.lang.Readable
  • 预期的继承是契约的一部分,禁止 lambda 表达式实现,例如:应该由 a 实现,由 a 实现,同样适用于(嘿,两个 s 用于完全相同的东西...),wheras 应该由子类实现java.awtActiveEventAWTEventPrinterGraphicsGraphicsjava.awt.print.PrinterGraphicsinterfacejavax.print.FlavorExceptionjavax.print.PrintException
  • 我不知道各种事件侦听器接口是否没有标记为与其他不能成为功能接口的多方法事件侦听器的对称性,但实际上事件侦听器是lambda表达式的良好候选者。如果你想在以后删除一个监听器,你必须存储实例,但这没有什么不同,例如内部类监听器实现。@FunctionalInterface
  • 库维护者有一个庞大的代码库,其中包含200多种候选类型,并且没有资源来讨论是否应该对其进行注释,因此专注于在功能上下文中使用的主要候选项。我敢肯定,例如,, , juc & 不会很糟糕,但我不知道是否,例如 成为一个好的候选人。库越通用,库的用户就越有可能为他们感兴趣的特定问题回答这个问题,但是坚持让库维护者为所有接口回答这个问题是不公平的。interfacejava.io.ObjectInputValidationjava.lang.reflect.InvocationHandlerRejectedExecutionHandlerThreadFactory@FunctionalInterfacejava.security.spec.ECFieldinterface

    在这种情况下,将 a 的存在视为一条消息,即 a 肯定打算与 lambda 表达式一起使用,而不是将缺少注释视为不打算以这种方式使用的指示器更有意义。这与编译器处理它完全一样,您可以使用lambda表达式实现每个抽象方法,但是当注释存在时,它将确保您可以以这种方式使用它。@FunctionalInterfaceinterfaceinterfaceinterface


答案 2

计划扩展。仅仅因为接口符合现在SMI的要求并不意味着以后不需要扩展。