为什么@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
具有编程语言语义,例如AutoClosable
或Iterable
(对于您自己的接口不太可能发生) - 不期望
interface
具有任意实现和/或更多是标识符而不是实际实现,例如java.net.ProtocolFamily
或java.lang.reflect.GenericArrayType
(注意后者也将inheritancegetTypeName()
的default
实现getTypeName()
依赖于toString()
对lambda实现无用 -
此
interface
的实例应具有标识,例如java.net.ProtocolFamily
,java.nio.file.WatchEvent.Modifier
等。请注意,这些通常由enum
实现另一个例子是
java.time.chrono.Era
,它碰巧只有一个abstract
方法,但它的规范说“可以使用==
运算符比较Era
实例”。 - 该
interface
旨在改变操作的行为,对于该操作,interface
的实现没有inheritance/实现任何其他内容是没有意义的,例如java.rmi.server.Unreferenced
- 它是类的常见操作的抽象,它应该不仅仅包含这些操作,例如
java.io.Closeable
,java.io.Flushable
,java.lang.Readable
- 预期的inheritance是合同的一部分并且禁止lambda表达式实现,例如在
java.awt
:ActiveEvent
应该由AWTEvent
实现,PrinterGraphics
由Graphics
,同样适用于java.awt.print.PrinterGraphics
(嘿,两个interface
s)对于完全相同的事情……),应该通过javax.print.PrintException
子类实现whesjavax.print.FlavorException
- 我不知道各种事件监听器接口是否没有用
@FunctionalInterface
标记,以便与其他多方法事件监听器对称,而这些监听器不能是function接口,但实际上事件监听器是lambda表达式的良好候选者。 如果要在以后删除侦听器,则必须存储实例,但这与实例内部类侦听器没有区别。 -
库维护者拥有一个包含200多种候选类型的大型代码库,而不是讨论每个
interface
的资源,无论是否应该注释,因此关注于在function上下文中使用的主要候选者。 我敢肯定,例如java.io.ObjectInputValidation
,java.lang.reflect.InvocationHandler
,jucRejectedExecutionHandler
和ThreadFactory
不会像@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定义的所有标准。