173

我在 Java 8 中遇到了一个新术语:“函数式接口”。在使用lambda 表达式时,我只能找到它的一种用途。

Java 8 提供了一些内置的函数式接口,如果我们想定义任何函数式接口,那么我们可以使用@FunctionalInterface注解。它将允许我们在接口中只声明一个方法。

例如:

@FunctionalInterface
interface MathOperation {
    int operation(int a, int b);
}

除了使用lambda 表达式之外,它在 Java 8 中还有多大用处?

这里的问题与我问的问题不同。它问为什么我们在使用 lambda 表达式时需要函数式接口。我的问题是:除了使用 lambda 表达式之外,函数式接口的其他用途是什么?)

4

11 回答 11

139

@FunctionalInterface注释对于代码的编译时间检查很有用。static除了 之外,您不能拥有多个方法,default以及覆盖Object@FunctionalInterface或任何其他用作功能接口的接口中的方法的抽象方法。

但是您可以使用不带此注释的 lambda,也可以覆盖不带@Override注释的方法。

来自文档

函数式接口只有一个抽象方法。由于默认方法有一个实现,它们不是抽象的。如果一个接口声明了一个覆盖 java.lang.Object 的公共方法之一的抽象方法,这也不会计入接口的抽象方法计数,因为该接口的任何实现都将具有来自 java.lang.Object 或其他地方的实现

可以在 lambda 表达式中使用:

public interface Foo {
  public void doSomething();
}

不能在 lambda 表达式中使用:

public interface Foo {
  public void doSomething();
  public void doSomethingElse();
}

但这会产生编译错误

@FunctionalInterface
public interface Foo {
  public void doSomething();
  public void doSomethingElse();
}

'@FunctionalInterface' 注释无效;Foo 不是函数式接口

于 2016-04-27T06:30:35.810 回答
23
于 2016-04-27T08:34:19.113 回答
14

正如其他人所说,功能接口是公开一种方法的接口。它可能有不止一种方法,但所有其他方法都必须有一个默认实现。它被称为“功能接口”的原因是因为它有效地充当了一个函数。由于您可以将接口作为参数传递,这意味着函数现在是“一等公民”,就像在函数式编程语言中一样。这有很多好处,您会在使用 Stream API 时看到很多。当然,lambda 表达式是它们的主要用途。

于 2016-04-27T14:39:56.023 回答
13

一点也不。Lambda 表达式是该注释的唯一要点。

于 2016-04-27T06:25:24.203 回答
7

可以将 lambda 表达式分配给函数式接口类型,但方法引用和匿名类也可以。

关于特定功能接口的一个好处是,由于它们包含方便的默认方法java.util.function,它们可以组合以创建新功能(如Function.andThenand Function.compose、等)。Predicate.and

于 2016-04-27T06:46:44.777 回答
6

只有一个抽象方法的接口称为功能接口。使用@FunctionalInterface 不是强制性的,但最好将它与函数式接口一起使用,以避免意外添加额外的方法。如果接口使用@FunctionalInterface 注解,并且我们尝试使用多个抽象方法,则会引发编译器错误。

package com.akhi;
    @FunctionalInterface
    public interface FucnctionalDemo {

      void letsDoSomething();
      //void letsGo();      //invalid because another abstract method does not allow
      public String toString();    // valid because toString from Object 
      public boolean equals(Object o); //valid

      public static int sum(int a,int b)   // valid because method static
        {   
            return a+b;
        }
        public default int sub(int a,int b)   //valid because method default
        {
            return a-b;
        }
    }
于 2018-09-26T05:52:35.563 回答
4

功能接口:

  • 在 Java 8 中引入
  • 包含“单一抽象”方法的接口。

示例 1:

   interface CalcArea {   // --functional interface
        double calcArea(double rad);
    }           

示例 2:

interface CalcGeometry { // --functional interface
    double calcArea(double rad);
    default double calcPeri(double rad) {
        return 0.0;
    }
}       

示例 3:

interface CalcGeometry {  // -- not functional interface
    double calcArea(double rad);
    double calcPeri(double rad);
}   

Java8注解——@FunctionalInterface

  • 注解检查接口只包含一个抽象方法。如果不是,则引发错误。
  • 即使缺少@FunctionalInterface,它仍然是功能接口(如果有单个抽象方法)。注释有助于避免错误。
  • 功能接口可能有额外的静态和默认方法。
  • 例如 Iterable<>、Comparable<>、Comparator<>。

功能接口的应用:

  • 方法参考
  • Lambda 表达式
  • 构造函数引用

学习函数式接口,首先学习接口中的默认方法,学完函数式接口后,你会很容易理解方法引用和lambda表达式

于 2018-12-18T12:53:14.727 回答
2

您可以在 Java 8 中使用 lambda

public static void main(String[] args) {
    tentimes(inputPrm - > System.out.println(inputPrm));
    //tentimes(System.out::println);  // You can also replace lambda with static method reference
}

public static void tentimes(Consumer myFunction) {
    for (int i = 0; i < 10; i++)
        myFunction.accept("hello");
}

有关Java LambdaFunctionalInterfaces的更多信息

于 2018-09-17T06:06:05.890 回答
1

@FunctionalInterface是 Java 8 发布的一个新注解,它为 lambda 表达式提供目标类型,并用于代码的编译时检查。

当你想使用它时:

1-你的接口不能有多个抽象方法,否则会出现编译错误。

1-您的接口应该是纯的,这意味着功能接口旨在由无状态类实现,纯的示例是Comparator接口,因为它不依赖于实现者状态,在这种情况下不会出现编译错误,但在很多情况下你无法将 lambda 与此类接口一起使用

java.util.function包包含各种通用功能接口,例如PredicateConsumerFunctionSupplier

另请注意,您可以在没有此注释的情况下使用 lambda。

于 2018-07-11T12:13:10.787 回答
1

除了其他答案之外,我认为“为什么使用函数式接口而不是直接使用 lambda 表达式”的主要原因可能与面向对象的 Java 语言的性质有关。

Lambda 表达式的主要属性有: 1. 可以左右传递 2. 可以在未来特定时间(多次)执行。现在为了在语言中支持这个特性,其他一些语言只是简单地处理这个问题。

例如,在 Java Script 中,函数(匿名函数或函数字面量)可以作为对象来寻址。因此,您可以简单地创建它们,也可以将它们分配给变量等等。例如:

var myFunction = function (...) {
    ...;
}
alert(myFunction(...));

或者通过 ES6,你可以使用箭头函数。

const myFunction = ... => ...

到目前为止,Java 语言设计者还没有接受通过这些方式处理提到的特性(函数式编程技术)。他们认为 Java 语言是面向对象的,因此他们应该通过面向对象的技术来解决这个问题。他们不想错过 Java 语言的简单性和一致性。

因此,他们使用接口,因为当需要只有一种方法的接口对象(我的意思是功能接口)时,您可以将其替换为 lambda 表达式。如:

ActionListener listener = event -> ...;
于 2018-09-14T13:44:00.140 回答
0

功能接口:如果接口具有单个抽象方法,而与默认或静态方法的数量无关,则该接口称为功能接口。函数接口用于 lamda 表达式。Runnable, Callable, Comparable,ComparatorFunctional接口的几个例子。

重点说明:

  • 使用注释@FunctionalInterface(可选)。
  • 它应该只有 1 个抽象方法(与默认方法和静态方法的数量无关)。
  • 两个抽象方法给出编译错误(@FunctionalInterface使用了提供者注解)。

线程更详细地讨论了功能接口对匿名类的好处以及如何使用它们。

于 2020-11-25T07:27:05.663 回答