📜  Java中的函数式接口

📅  最后修改于: 2022-05-13 01:55:33.604000             🧑  作者: Mango

Java中的函数式接口

Java永远是一种面向对象的编程语言。通过面向对象的编程语言,我们可以声明Java编程语言中存在的所有内容都在整个对象中循环,除了一些原始数据类型和原始方法以保持完整性和简单性。在称为Java的编程语言中不存在单独的函数。 Java编程语言中的函数是类的一部分,如果有人想使用它们,就必须使用该类的类或对象来调用任何函数。

功能接口是只包含一个抽象方法的接口。它们只能展示一种功能。从Java 8 开始,lambda 表达式可用于表示函数接口的实例。一个函数式接口可以有任意数量的默认方法。 RunnableActionListenerComparable是功能接口的一些示例。

功能接口也被认为是单一抽象方法接口。简而言之,它们也被称为SAM 接口。 Java中的函数式接口是为用户提供基本编程方法的新特性。

函数式接口包含在Java SE 8 中,带有 Lambda 表达式和方法引用,以使代码更易读、更干净、更直接。功能接口是确保它们只包含一种抽象方法的接口。通过使用名为@FunctionalInterface注释表示接口来使用和执行功能接口。如前所述,函数式接口只能包含一个抽象方法。但是,它们可以包含任意数量的默认和静态方法。

在函数式接口中,不需要使用 abstract 关键字,因为使用 abstract 关键字是可选的,因为默认情况下,接口内部定义的方法只是抽象的。我们也可以将 Lambda 表达式称为函数式接口的实例。

在Java 8 之前,我们必须创建匿名内部类对象或实现这些接口。

Java
// Java program to demonstrate functional interface
  
class Test {
    public static void main(String args[])
    {
        // create anonymous inner class object
        new Thread(new Runnable() {
            @Override public void run()
            {
                System.out.println("New thread created");
            }
        }).start();
    }
}


Java
// Java program to demonstrate Implementation of
// functional interface using lambda expressions
  
class Test {
    public static void main(String args[])
    {
  
        // lambda expression to create the object
        new Thread(() -> {
            System.out.println("New thread created");
        }).start();
    }
}


Java
// Java program to demonstrate lambda expressions to
// implement a user defined functional interface.
  
@FunctionalInterface
  
interface Square {
    int calculate(int x);
}
  
class Test {
    public static void main(String args[])
    {
        int a = 5;
  
        // lambda expression to define the calculate method
        Square s = (int x) -> x * x;
  
        // parameter passed and return type must be
        // same as defined in the prototype
        int ans = s.calculate(a);
        System.out.println(ans);
    }
}


Java
// A simple program to demonstrate the use
// of predicate interface
  
import java.util.*;
import java.util.function.Predicate;
  
class Test {
    public static void main(String args[])
    {
  
        // create a list of strings
        List names = Arrays.asList(
            "Geek", "GeeksQuiz", "g1", "QA", "Geek2");
  
        // declare the predicate type as string and use
        // lambda expression to create object
        Predicate p = (s) -> s.startsWith("G");
  
        // Iterate through the list
        for (String st : names) {
            // call the test method
            if (p.test(st))
                System.out.println(st);
        }
    }
}


输出
New thread created

从Java 8 开始,我们可以将 lambda 表达式分配给它的函数式接口对象,如下所示:

Java

// Java program to demonstrate Implementation of
// functional interface using lambda expressions
  
class Test {
    public static void main(String args[])
    {
  
        // lambda expression to create the object
        new Thread(() -> {
            System.out.println("New thread created");
        }).start();
    }
}
输出
New thread created

@FunctionalInterface 注解

@FunctionalInterface 注解用于保证函数式接口不能有多个抽象方法。如果存在多个抽象方法,编译器会标记“Unexpected @FunctionalInterface annotation”消息。但是,使用此注释不是强制性的。

Java

// Java program to demonstrate lambda expressions to
// implement a user defined functional interface.
  
@FunctionalInterface
  
interface Square {
    int calculate(int x);
}
  
class Test {
    public static void main(String args[])
    {
        int a = 5;
  
        // lambda expression to define the calculate method
        Square s = (int x) -> x * x;
  
        // parameter passed and return type must be
        // same as defined in the prototype
        int ans = s.calculate(a);
        System.out.println(ans);
    }
}
输出
25

一些内置的Java功能接口

从Java SE 1.8 开始,有很多接口被转换为函数式接口。所有这些接口都使用@FunctionalInterface 进行注释。这些接口如下——

  • Runnable –>这个接口只包含 run() 方法。
  • Comparable –>这个接口只包含 compareTo() 方法。
  • ActionListener –>这个接口只包含 actionPerformed() 方法。
  • Callable –>这个接口只包含 call() 方法。

Java SE 8 包括四种主要的功能接口,可以在多种情况下应用。这些都是:

  1. 消费者
  2. 谓词
  3. 函数
  4. 供应商

在前面的四个接口中,前三个接口,即 Consumer、Predicate 和函数,同样有下面提供的附加内容——

  1. 消费者 -> 双向消费者
  2. 谓词->双谓词
  3. 函数-> 双函数、一元运算符、二元运算符

1. 消费者

功能接口的消费者接口是只接受一个参数或绅士化参数的接口。消费者接口没有返回值。它什么也不返回。 Consumer 还有一些功能变体——DoubleConsumer、IntConsumer 和 LongConsumer。这些变体接受原始值作为参数。

除了这些变体之外,还有一种消费者界面的变体,称为 Bi-Consumer。

Bi-Consumer – Bi-Consumer 是消费者界面中最令人兴奋的变体。消费者接口只接受一个参数,但另一方面,Bi-Consumer 接口接受两个参数。 Consumer 和 Bi-Consumer 都没有返回值。它还返回注释,就像消费者界面一样。它用于遍历映射的条目。

消费者功能接口的语法/原型 –

Consumer consumer = (value) -> System.out.println(value);

Java Consumer 功能接口的此实现打印作为参数传递给打印语句的值。此实现使用Java的 Lambda函数。

2.谓词

在科学逻辑中,接受参数并作为回报生成布尔值作为答案的函数称为谓词。类似地,在Java编程语言中, Java的谓词函数式接口是一种函数类型,它接受单个值或参数并对其进行某种处理,并返回布尔值(真/假)答案。 Predicate 功能接口的实现还封装了Java中的过滤逻辑(用于根据提供的谓词过滤流组件的过程)。

就像 Consumer 函数式接口一样,Predicate 函数式接口也有一些扩展。它们是 IntPredicate、DoublePredicate 和 LongPredicate。这些类型的谓词功能接口只接受原始数据类型或值作为参数。

Bi-Predicate – Bi-Predicate 也是 Predicate 功能接口的扩展,它接受两个参数,而不是一个,进行一些处理,并返回布尔值。

谓词功能接口的语法 -

public interface Predicate {
 
    boolean test(T t);
 
}

谓词功能接口也可以使用类来实现。使用类实现谓词功能接口的语法如下 -

public class CheckForNull implements Predicate {
 
    @Override
    public boolean test(Object o) {
 
        return o != null;
 
    }
}

Java谓词功能接口也可以使用 Lambda 表达式来实现。 Predicate 功能接口的实现示例如下:

Predicate predicate = (value) -> value != null;

这种使用Java Lambda 表达式在Java中实现的功能接口比使用类实现的更易于管理和有效,因为两种实现都在做同样的工作,即返回相同的输出。

三、函数

函数是Java中的一种功能接口,它只接收一个参数并在所需的处理后返回一个值。 函数接口有很多版本,因为原始类型不能隐含通用类型参数,所以我们需要这些版本的函数接口。许多不同版本的函数接口都是有用的,通常用于基本类型,如 double、int、long。这些原始类型的不同序列也用于参数中。

这些版本是:

Bi-Function – Bi-Function 与函数基本相关。此外,它接受两个参数,而函数接受一个参数。

Bi-Function 的原型和语法如下:

@FunctionalInterface
public interface BiFunction 
{
 
   R apply(T t, U u);
    .......
 
}

在上面的接口代码中,T,U是输入,只有一个输出是R。

一元运算符和二元运算符——还有另外两个功能接口,分别称为一元运算符和二元运算符。它们都分别扩展了函数和 Bi-Function。简单来说,一元运算符扩展了函数,二元运算符扩展了 Bi-Function 。

一元运算符二元运算的原型如下 -

1. 一元运算符

@FunctionalInterface
public interface UnaryOperator extends Function 
{
    ……...
}

2.二元运算符

@FunctionalInterface
public interface BinaryOperator extends BiFunction 
{
    ……...
}

我们可以理解前面的例子,一元运算符只接受一个参数并且只返回一个参数。尽管如此,在一元运算符中,输入值和输出值都必须相同且类型相同。

另一方面,二元运算符接受两个值并返回一个与 Bi- 函数相当的值,但与一元运算符类似,输入和输出值类型必须相同且类型相同。

4. 供应商

供应商功能接口也是一种不接受任何输入或参数但返回单个输出的功能接口。这种类型的函数式接口一般用于值的惰性生成。供应商功能接口也用于定义生成任何序列的逻辑。例如 – 斐波那契数列背后的逻辑可以在 Stream.generate 方法的帮助下生成,该方法由供应商功能接口实现。

供应商功能接口的不同扩展包含许多其他供应商功能,如 BooleanSupplier、DoubleSupplier、LongSupplier 和 IntSupplier。所有这些进一步特化的返回类型只是它们对应的原语。

供应商功能接口的语法/原型是 -

@FunctionalInterface
public interface Supplier{
 
// gets a result
………….
 
// returns the specific result
…………
 
T.get();
 
}

Java

// A simple program to demonstrate the use
// of predicate interface
  
import java.util.*;
import java.util.function.Predicate;
  
class Test {
    public static void main(String args[])
    {
  
        // create a list of strings
        List names = Arrays.asList(
            "Geek", "GeeksQuiz", "g1", "QA", "Geek2");
  
        // declare the predicate type as string and use
        // lambda expression to create object
        Predicate p = (s) -> s.startsWith("G");
  
        // Iterate through the list
        for (String st : names) {
            // call the test method
            if (p.test(st))
                System.out.println(st);
        }
    }
}
输出
Geek
GeeksQuiz
Geek2

要点/观察

以下是关于Java中的函数式接口的一些重要观点:

  1. 在函数式接口中,只支持一种抽象方法。如果函数接口的注解,即@FunctionalInterface 没有用函数接口实现或编写,则可以在其中声明多个抽象方法。但是,在具有多个功能接口的这种情况下,该接口将不会被称为功能接口。它被称为非功能接口。
  2. 不需要 @FunctionalInterface 注释,因为它只是自愿的。这是因为它有助于检查编译器级别而编写的。除此之外,它是可选的。
  3. 可以将无限数量的方法(无论是静态的还是默认的)添加到功能接口中。简而言之,包含静态和默认方法的功能接口是没有限制的。
  4. 覆盖父类的方法不会违反Java中函数式接口的规则。
  5. Java.util。 函数包包含许多Java 8 中内置的功能接口。