java - 为什么@FunctionalInterface没有在合格的JDK的所有接口(interface)上使用?

标签 java functional-programming java-8 functional-interface

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

有带有此批注的43 interfaces in the java.util.function package。在jdk.1.8.0/src中搜索@FunctionalInterface只会发现57次匹配。为什么其他可能添加了@FunctionalInterface的接口(interface)(例如AutoCloseable)仍然缺少它?

annotations documentation中有一些模糊的提示:

“一种有用的注释类型,用于指示接口(interface)类型声明为,打算将用作功能接口(interface)”

是否有充分的理由不让打算让用作我设计的接口(interface)(可能只是一个功能接口(interface))而不能用作一个接口(interface)?除了没有意识到可以添加它以外,是否还留下了其他任何指示?

难道不是在任何已发布的接口(interface)上添加抽象方法都会使实现它的任何人(无论是否起作用)都陷入困境吗?假设他们只是不想打扰他们,我会感到愤世嫉俗,但是还有什么其他的解释呢?

更新:查看"Should 'Comparable' be a 'Functional interface'?"后,我仍然遇到困扰的问题。当单一方法接口(interface)和功能接口(interface)在结构上相同时,还有什么不同?区别仅仅是名称吗? Comparable和Comparator在语义上足够接近。事实证明它们在结构上有所不同,因此仍然不是最好的例子。

是否存在一种情况,即SMI在结构上可以用作功能接口(interface),但仍不鼓励使用接口(interface)名称和方法的语义含义?还是Javadocs暗示的契约(Contract)?

最佳答案

好吧,如果您假设总是给出该意图,那么注释该意图的注释将毫无用处。

您为示例AutoCloseable命名了该示例,但显然不打算将其实现为函数,因为存在Runnable,对于具有()->void签名的函数而言,此便捷得多。旨在实现AutoCloseable的类管理外部资源,而通过lambda表达式实现的匿名类则不会。
Comparable是一个更清晰的示例,interface不仅不打算作为lambda表达式实现,而且不可能使用lambda表达式正确实现。

例如,未使用interface标记@FunctionalInterface的可能原因:

  • interface具有编程语言语义,例如AutoClosableIterable(您自己的界面不太可能发生)
  • 我们不希望interface具有任意实现和/或比实际实现更多的标识符,例如java.net.ProtocolFamilyjava.lang.reflect.GenericArrayType(请注意,后者也将继承default实现,因为getTypeName()对于依赖于toString()的lambda实现无用)
  • interface的实例应具有标识,例如java.net.ProtocolFamilyjava.nio.file.WatchEvent.Modifier等。请注意,这些通常由enum实现

    另一个示例是java.time.chrono.Era,它碰巧只有一个abstract方法,但是its specification说:“可以使用Era运算符比较==的实例。”
  • interface旨在更改操作的行为,对此interface的实现而不继承/实现其他任何意义都没有意义,例如java.rmi.server.Unreferenced
  • 这是对类的常见操作的抽象,它不仅应具有这些操作,例如java.io.Closeablejava.io.Flushablejava.lang.Readable
  • 预期继承是契约(Contract)的一部分,并禁止使用lambda表达式实现,例如在java.awt中:ActiveEvent应该由AWTEvent实现,PrinterGraphicsGraphics实现,java.awt.print.PrinterGraphics同样适用(嘿,两个ozt_code完全相同……),而interface应该由javax.print.FlavorException子类
  • 实现
  • 我不知道各个事件侦听器接口(interface)是否未标记javax.print.PrintException以便与不能作为功能接口(interface)的其他多方法事件侦听器对称,但是实际上,事件侦听器是lambda表达式的理想选择。如果您想在以后删除监听器,则必须存储该实例,但这与例如内部类侦听器实现。
  • 库维护人员拥有一个庞大的代码库,其中包含200多种候选类型,而不是为每个@FunctionalInterface讨论是否应对其进行注释的资源,因此将重点放在在功能上下文中使用的主要候选对象上。我敢肯定,例如interfacejava.io.ObjectInputValidation,juc java.lang.reflect.InvocationHandlerRejectedExecutionHandlerThreadFactory一样不错,但我不知道是否@FunctionalInterface是一个不错的选择。库越通用,库的用户越有可能针对他们感兴趣的特定java.security.spec.ECField回答该问题,但是坚持要求库维护者为所有接口(interface)回答该问题将是不公平的。

    在这种情况下,将interface作为消息来表明@FunctionalInterface肯定是可以与lambda表达式一起使用的,这比将注解的缺失作为不被使用的指示符更有意义。办法。就像编译器处理它一样,您可以使用lambda表达式实现每个抽象方法interface,但是当存在注释时,它将确保您可以这种方式使用此interface
  • 关于java - 为什么@FunctionalInterface没有在合格的JDK的所有接口(interface)上使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28166187/

    相关文章:

    scala - 来自Scala编程的功能性队列

    Haskell 反向函数

    java - 使用普通 JAVA Stream 收集 int 数组的值

    java - 程序抛出 IllegalThreadStateException

    java - ArrayList排序不影响ArrayList

    java - 将图标添加到 jTable 的不同行中

    java - 如何在Fabric8 Open Jdk Container中启用扩展编码?

    haskell - 简化 boolean 表达式的函数

    java - 为什么不推荐基于 AtomicInteger 的 Stream 解决方案?

    java - Keycloak java.lang.NoClassDefFoundError : java/security/acl/Group using Springboot