Java 8中用于什么功能接口?

问题描述 投票:143回答:10

我在Java 8中遇到了一个新术语:“功能接口”。在使用lambda expressions时,我只能找到它的一种用法。

Java 8提供了一些内置的功能接口,如果我们想定义任何功能接口,则可以使用@FunctionalInterface批注。它将允许我们在接口中仅声明一个方法。

例如:

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

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

here问题与我问的问题不同。它问的是为什么在使用lambda表达式时我们需要功能接口。我的问题是:为什么功能接口除了lambda表达式以外还有其他用途?]

java lambda interface java-8
10个回答
123
投票

@FunctionalInterface批注对于检查代码的编译时间很有用。除了staticdefault和用于覆盖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不是功能界面


1
投票

功能接口:

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

12
投票

documentation实际上在目的之间有所不同

一种说明性注释类型,用于指示接口类型声明旨在作为Java语言规范定义的功能接口

和用例

请注意,可以使用lambda表达式,方法引用或构造函数引用来创建功能接口的实例。

其用语通常不排除其他用例。由于主要目的是指示功能接口,所以您的实际问题归结为“是否还有其他用例功能接口除了lambda表达式和方法/构造函数引用?”] >

由于功能接口

是Java语言规范定义的Java语言构造,因此只有该规范才能回答该问题:

JLS §9.8. Functional Interfaces

除了通过声明和实例化类来创建接口实例的常规过程(第15.9节)之外,还可以使用方法引用表达式和lambda表达式(第15.13节,第15.27节)创建功能接口的实例。

因此Java语言规范没有另外说明,该部分提到的唯一用例是使用方法引用表达式和lambda表达式创建接口实例。 (这包括构造函数引用,因为它们在规范中被称为方法引用表达式的一种形式。)>

所以一句话,不,在Java 8中没有其他用例。

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

完全没有。 Lambda表达式是该注释的唯一点。

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

关于java.util.function中特定功能接口的一件好事是,由于它们包含的方便的默认方法,它们可以组成新的功能(例如Function.andThenFunction.composePredicate.and等)。

仅具有一种抽象方法的接口称为功能接口。并非必须使用@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;
        }
    }

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

当您想使用它时:

1-您的接口必须

具有多个抽象方法,否则将给出编译错误。

1-您的接口应该是纯接口,这意味着功能接口旨在由无状态类实现,纯接口的示例是Comparator接口,因为它不依赖于实现者状态,在这种情况下

将会给出编译错误,但是在许多情况下,您将无法在此类接口上使用lambda

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

也请注意,您可以使用不带此批注的lambda。

您可以在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 LambdasFunctionalInterfaces的更多信息,>

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

Lambda表达式的主要属性是:1.它们可以传递2.可以在将来的特定时间(几次)执行。现在,为了以语言支持此功能,其他一些语言仅处理此问题。

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

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

或通过ES6,您可以使用箭头功能。

const myFunction = ... => ...

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

因此,它们使用接口,因为当只需要一个方法(我的意思是功能接口)的接口的对象需要用lambda表达式替换时。如:

ActionListener listener = event -> ...;

功能接口:

  • 在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表达式


12
投票

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


10
投票

完全没有。 Lambda表达式是该注释的唯一点。


5
投票

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


5
投票

仅具有一种抽象方法的接口称为功能接口。并非必须使用@FunctionalInterface,但最好的做法是将其与功能接口一起使用,以避免意外添加其他方法。如果使用@FunctionalInterface注释对接口进行注释,并且我们尝试使用多个抽象方法,则它将引发编译器错误。


2
投票

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


2
投票

您可以在Java 8中使用lambda


1
投票

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

Lambda表达式的主要属性是:1.它们可以传递2.可以在将来的特定时间(几次)执行。现在,为了以语言支持此功能,其他一些语言仅处理此问题。

© www.soinside.com 2019 - 2024. All rights reserved.