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

时间:2015-01-27 08:36:34

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

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

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

annotations documentation中有一点含糊的暗示:

"信息性注释类型,用于指示界面类型声明意图是一个功能界面"

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

是否不会将抽象方法添加到任何已发布的界面,以阻止任何人实现它,功能与否?我觉得他们只是没有费心去追捕他们,但是还有其他解释,我感到愤世嫉俗?

更新:在查看"Should 'Comparable' be a 'Functional interface'?"后,我发现我仍然有唠叨的问题。当单一方法接口和功能接口在结构上相同时,它们会有什么不同?简单的名称是不同的? Comparable和Comparator在语义上足够接近。事实证明它们在结构上是不同的,但仍然不是最好的例子......

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

3 个答案:

答案 0 :(得分:20)

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

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

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


未通过示例标记interface interface的可能原因:

  • @FunctionalInterface具有编程语言语义,例如interfaceAutoClosable(这不太可能发生在您自己的界面上)
  • 预计Iterable不具有任意实现和/或不是实际实现的标识符,例如interfacejava.net.ProtocolFamily(请注意,后者也会继承java.lang.reflect.GenericArrayType default实现,因为getTypeName()依赖于toString()
  • 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
  • 预期的继承是合同的一部分,并禁止lambda表达式实现,例如在java.awtActiveEvent应该由AWTEventPrinterGraphicsGraphics实施,同样适用于java.awt.print.PrinterGraphics(嘿,两个{ {1}}对于完全相同的事情...),interface应该由javax.print.FlavorException子类实现
  • 我不知道各种事件监听器接口是否都没有用javax.print.PrintException标记与其他多方法事件监听器的对称性,这些监听器不能是功能接口,但实际上事件监听器是lambda的良好候选者表达式。如果你想在以后删除一个监听器,你必须存储实例,但这与实例没有区别,例如内部类监听器实现。
  • 库维护者拥有一个包含200多种候选类型的大型代码库,而不是每个@FunctionalInterface讨论的资源是否应该注释,因此专注于在功能中使用的主要候选者上下文。我敢肯定,例如, interfacejava.io.ObjectInputValidation,juc java.lang.reflect.InvocationHandler& RejectedExecutionHandler不会像ThreadFactory那样糟糕,但我不知道是否,例如@FunctionalInterface是一个很好的候选人。图书馆越普遍,图书馆的用户就越有可能为他们感兴趣的特定java.security.spec.ECField回答这个问题,但坚持图书馆维护人员为所有接口。

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

答案 1 :(得分:2)

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

答案 2 :(得分:0)

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

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

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

例如,请查看以下代码。

public interface Comparable<T> {
   public int compareTo(T o);
}

@FunctionalInterface
public interface ToIntFunction<T> {
   int applyAsInt(T value);
}

public static void main(String[] args){
   ToIntFunction<String> f = str -> Integer.parseInt(str);
   Comparable<String> c = str -> Integer.parseInt(str);
}

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