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

can*_*nge 16 java functional-programming java-8 functional-interface

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

java.util.function包中43个接口,带有此批注.搜索jdk.1.8.0/src @FunctionalInterface只能获得57次点击.为什么其他可能添加的接口(如AutoCloseable)@FunctionalInterface仍然缺少它?

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

"用于指示接口类型声明旨在成为功能接口的信息性注释类型"

有没有什么好的理由不打算我设计的接口(可能只是一个功能接口)不能用作一个接口?除了没有意识到它可能被添加之外,是否有任何迹象?

是不是将抽象方法添加到任何已发布的接口来阻止实现它的任何人,功能与否?我觉得玩世不恭,假设他们只是懒得去追捕他们,但其他解释是什么?

更新:看过"应该'可比'是一个'功能界面'?" 我发现我仍然有唠叨的问题.当单一方法接口和功能接口在结构上相同时,它们会有什么不同?简单的名称是不同的?Comparable和Comparator在语义上足够接近.事实证明它们在结构上是不同的,但仍然不是最好的例子......

是否有一种情况,SMI在结构上很好用作功能接口,但仍然不鼓励接口名称和方法的语义含义?或者也许是Javadocs隐含的合同?

Hol*_*ger 21

好吧,如果你假设总是给出意图,那么记录意图的注释将毫无用处.

您将该示例命名AutoCloseable为显然不是作为函数实现的,因为Runnable对于具有()->void签名的函数来说更方便.它旨在实现一个类AutoCloseable管理外部资源,通过lambda表达式实现的匿名类不能这样做.

更清楚的例子是Comparable,interface不仅不打算将其实现为lambda表达式,使用lambda表达式也无法正确实现它.


不标记的原因可能interface@FunctionalInterface通过例如:

  • interface具有编程语言的语义,如AutoClosableIterable(这是不可能发生的为自己的接口)
  • 不期望interface具有任意实现和/或更多是标识符而不是实际实现,例如java.net.ProtocolFamily,或者java.lang.reflect.GenericArrayType(注意后者也将继承default对于getTypeName()依赖于lambda实现无用的实现toString())
  • 这样做的情况下,interface应该有一个身份,例如java.net.ProtocolFamily,java.nio.file.WatchEvent.Modifier等等.需要注意的是,这些通常由实施enum

    另一个例子是java.time.chrono.Era恰好只有一个abstract方法,但其规范说" Era可以使用==运算符对实例进行比较".

  • interface是为了改变一个操作的其中一个实施的行为interface不继承/实现别的是没有意义的,如java.rmi.server.Unreferenced
  • 它的类的常见操作的抽象模型,它应该具有的不仅仅是这些操作,例如更多java.io.Closeable,java.io.Flushable,java.lang.Readable
  • 预期继承是合同的一部分,并禁止lambda表达式实现,例如在java.awt:ActiveEvent应当由执行AWTEvent,PrinterGraphicsGraphics,同样适用于java.awt.print.PrinterGraphics(嘿,双interfaceS表示完全一样的东西......),wheras javax.print.FlavorException应由执行javax.print.PrintException
  • 我不知道各种事件监听器接口是否没有标记@FunctionalInterface为与其他多方法事件监听器不对称的对称性,但实际上事件监听器是lambda表达式的良好候选者.如果要在以后删除侦听器,则必须存储实例,但这与实例内部类侦听器没有区别.
  • 库维护者拥有一个包含200多种候选类型的大型代码库,而不是讨论每个interface是否应该注释的资源,因此专注于在功能上下文中使用的主要候选者.我敢肯定,例如java.io.ObjectInputValidation,java.lang.reflect.InvocationHandlerjuc RejectedExecutionHandler&ThreadFactory并不会坏,@FunctionalInterface但我不知道是否,例如,java.security.spec.ECField成为一个好的候选人.库越普遍,库的用户就越有可能针对interface他们感兴趣的特定问题回答这个问题,但坚持让库维护人员为所有接口回答它是不公平的.

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

  • @CandiedOrange`Comparator`采用两种类型`T`并比较它们 - 它是一个[`ToIntBiFunction <T,T>`](http://docs.oracle.com/javase/8/docs/api/java/util/功能/ ToIntBiFunction.html).`Comparable`将_itself_与其他类型进行比较 - 一个lambda(几乎)没有自我意识,所以这使得它无法实现为lambda. (5认同)
  • 这个。当然不是“未来扩张”。 (2认同)
  • @CandiedOrange:`Comparable`契约需要对称,即`a.compareTo(b)== -b.compareTo(a)`,这是不可能保证lambda表达式的; 你甚至不能声明lambda来实现`Comparable <T>`,`T`是lambda的类,因为lambda的类不符合规范. (2认同)
  • @CandiedOrange:不打算作为功能接口,不会阻止您通过lambda表达式或方法引用实现该接口.我已经使用`AutoClosable`和`Iterable'做了这个,虽然我知道这不在界面创建者的意图范围内.总是有一个预期的用途和实际用途,你必须要小心不要偏离预期的用途,但是,如果我们所有人都在核心开发人员所预见的路径上,那就太奇怪了...... (2认同)