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

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

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

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

“用于指示接口类型声明旨在成为function接口的信息性注释类型”

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

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

更新 :在查看“应该’可比’是’function界面’后?” 我发现我仍然有唠叨的问题。 当单一方法接口和function接口在结构上相同时,它们会有什么不同? 简单的名称是不同的? Comparable和Comparator在语义上足够接近。 事实certificate它们在结构上是不同的,但仍然不是最好的例子……

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

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

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

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


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

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

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

  • interface旨在改变操作的行为,对于该操作, interface的实现没有inheritance/实现任何其他内容是没有意义的,例如java.rmi.server.Unreferenced
  • 它是类的常见操作的抽象,它应该不仅仅包含这些操作,例如java.io.Closeablejava.io.Flushablejava.lang.Readable
  • 预期的inheritance是合同的一部分并且禁止lambda表达式实现,例如在java.awtActiveEvent应该由AWTEvent实现, PrinterGraphicsGraphics ,同样适用于java.awt.print.PrinterGraphics (嘿,两个interface s)对于完全相同的事情……),应该通过javax.print.PrintException子类实现whes javax.print.FlavorException
  • 我不知道各种事件监听器接口是否没有用@FunctionalInterface标记,以便与其他多方法事件监听器对称,而这些监听器不能是function接口,但实际上事件监听器是lambda表达式的良好候选者。 如果要在以后删除侦听器,则必须存储实例,但这与实例内部类侦听器没有区别。
  • 库维护者拥有一个包含200多种候选类型的大型代码库,而不是讨论每个interface的资源,无论是否应该注释,因此关注于在function上下文中使用的主要候选者。 我敢肯定,例如java.io.ObjectInputValidationjava.lang.reflect.InvocationHandler ,juc RejectedExecutionHandlerThreadFactory不会像@FunctionalInterface那样糟糕,但我不知道是否,例如java.security.spec.ECField make一个好的候选人。 库越普遍,库的用户就越有可能为他们感兴趣的特定interface回答这个问题,但坚持让库维护者为所有接口回答它是不公平的。

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

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

在java 8中,函数接口是一个接口,它只有一个称为函数方法的抽象方法,lambda表达式的参数和返回类型匹配在该方法中。

java.util.function包含JDK使用的通用function接口,也可供最终用户使用 。 虽然它们不是lambda表达式可能适用的完整的function接口集,但它们提供了足以满足常见要求的function。 只要现有的设置不够,您就可以自由创建自己的function接口。

有许多这样的接口值得指定为function接口,但java.util.function包已经为我们几乎所有目的提供了function接口。

例如,请查看以下代码。

 public interface Comparable { public int compareTo(T o); } @FunctionalInterface public interface ToIntFunction { int applyAsInt(T value); } public static void main(String[] args){ ToIntFunction f = str -> Integer.parseInt(str); Comparable c = str -> Integer.parseInt(str); } 

Comparable也可以获取一个对象并派生一些int类型值,但是提供了一个更通用的专用接口ToIntFunction来执行此任务。 没有这样的硬性规则,所有值得的接口都应该用@FunctionalInterface注释,但为了获得lambda特性的优势,接口应该满足FunctionalInterface定义的所有标准。