Java 教程

Java 控制语句

面向对象编程

Java 内置类

Java 文件处理

Java 错误与异常

Java 多线程

Java 同步

Java 网络编程

Java 集合

Java 接口

Java 数据结构

Java 集合算法

高级 Java

Java 其他

Java APIs 与框架

Java 类引用

Java 有用资源

Java - 函数式接口



**函数式接口**是在 Java 8 中与lambda 表达式方法引用一起引入的。这三个特性是为了增强Java中的函数式编程,并编写简洁易读的代码。在 Java 8 之前,需要编写大量样板代码来实现基本功能。例如,为了调用一个函数,首先必须创建一个包含所需方法的类,创建一个类实例,然后使用该实例来调用方法,或者使用匿名类及其相应的方法。

使用 lambda 表达式,我们可以避免对具体类和匿名类对象的需要。**函数式接口**更进一步,因为 lambda 表达式可以很容易地实现函数式接口,因为它只需要实现一个方法。

**函数式接口**只有一个功能。例如,具有单个方法 compareTo() 的 Comparable 接口用于比较目的。但它可以有任意数量的默认方法和静态方法。

Java 8 定义了许多函数式接口,这些接口广泛用于 lambda 表达式中。以下是 java.util.Function 包中定义的函数式接口列表。

@FunctionalInterface 注解

从功能上讲,任何只有一个抽象方法的接口都是函数式接口。Java 提供了一个 @FunctionalInterface 注解,用于将接口标记为函数式接口,以便编译器可以检查接口是否为函数式接口。此注解是可选的,主要用于添加编译器检查,并提高代码的可读性和可维护性。

Java 中函数式接口的类型

Java 中主要有四种类型的函数式接口。

Predicate 函数式接口

谓词函数式接口是一种其方法接受一个参数并返回 true 或 false 的接口。谓词函数式接口主要用于比较排序元素或根据应用于传递输入的某些条件过滤值。Java 还为基本类型提供了谓词函数式接口,例如 IntPredicate、DoublePredicate 和 LongPredicate,它们分别只接受 Integer、Double 和 Long。

用法

Predicate predicate = (value) -> value  != 0;
// or
Predicate predicate = (value) -> test(value);

在上面的代码片段中,谓词函数根据传递的值返回 true/false。

示例

在这个例子中,我们使用谓词函数式接口来过滤整数列表中的奇数,借助 lambda 表达式。

package com.tutorialspoint;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Tester {
   public static void main(String args[]) {
      List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8);

      Predicate<Integer> isEvenNumber = n -> n %2 == 0;
      numbers =  numbers.stream().filter(isEvenNumber).toList();

      System.out.println(numbers);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

[2, 4, 6, 8]

Consumer 函数式接口

Consumer 函数式接口是一种其方法接受一个参数但不返回值的接口。Consumer 函数式接口主要用于副作用操作。例如,打印元素,添加问候语等。Consumer 也有其他变体,如 BiConsumer。BiConsumer 函数式接口可以接受两个参数。Java 还为基本类型提供了 consumer 函数式接口,例如 IntConsumer、DoubleConsumer 和 LongConsumer,它们分别只接受 Integer、Double 和 Long。

用法

Consumer consumer = (value) -> System.out.println(value);
// Or
Consumer consumer1 = System.out::println;
// Or
Consumer consumer2 = (value) -> accept(value);

示例

在这个例子中,我们使用 consumer 函数式接口来打印整数列表中的所有数字,借助 lambda 表达式和方法引用。

package com.tutorialspoint;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Tester {
   public static void main(String args[]) {
      List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8);

      Consumer<Integer> consumer = (value) -> System.out.println(value);
      Consumer consumer1 = System.out::println;

      System.out.println("Printing using consumer functional interface as lambda expression");
      numbers.forEach(consumer);

      System.out.println("Printing using consumer functional interface as method reference");
      numbers.forEach(consumer1);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

Printing using consumer functional interface as lambda expression
1
2
3
4
5
6
7
8
Printing using consumer functional interface as method reference
1
2
3
4
5
6
7
8

Supplier 函数式接口

Supplier 函数式接口是一种其方法没有任何参数并返回值的接口。Supplier 函数式接口主要用于延迟生成值。例如,获取随机数,生成数字序列等。

用法

Supplier supplier = () -> Math.random() * 10;
// or
Supplier supplier1 = () -> get();

示例

在这个例子中,我们使用 Supplier 函数式接口来获取随机数,借助 lambda 表达式。

package com.tutorialspoint;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class Tester {
   public static void main(String args[]) {
      Supplier<Integer> supplier = () -> (int)(Math.random() * 10);

      List<Integer> randomNumbers = new ArrayList<>();

      // generate 10 random numbers
      for(int i = 0; i< 10; i++) {
         randomNumbers.add(supplier.get());
      }
      System.out.println(randomNumbers);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

[0, 8, 8, 8, 8, 5, 7, 5, 5, 9]

Function 函数式接口

函数式接口是指其方法接受一个参数并返回一个值的方法。函数式接口主要用于获取处理后的值。例如,获取元素的平方、修剪字符串值等。Function还有其他变体,例如BiFunction。BiFunction函数式接口可以接受两个参数。Java也为基本数据类型提供了函数式接口,例如IntFunction、DoubleFunction和LongFunction,它们分别只接受Integer、Double和Long。还有两个实用程序接口,UnaryOperator扩展了Function接口,BinaryOperator扩展了BiFunction接口。

用法

Function function = (value) -> Math.random() * 10;
// or
Function function1 = (value) -> apply(value);

示例

在这个例子中,我们使用函数式接口和lambda表达式来获取数字平方的列表。

package com.tutorialspoint;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Tester {
   public static void main(String args[]) {
      List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8);

      Function<Integer, Integer> squared = (value) -> value * value;  

      List<Integer> squaredNumbers =  numbers.stream().map(squared).toList();

      System.out.println(squaredNumbers);
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

[1, 4, 9, 16, 25, 36, 49, 64]

Java 8之前已存在的函数式接口

在Java中,许多现有的接口都被注释为函数式接口,并且可以在lambda表达式中使用。例如:

  • Runnable − 提供run()方法

  • Callable − 提供call()方法

  • ActionListener − 提供actionPerformed()方法

  • Comparable − 提供compareTo()方法来比较两个数字

示例

在这个例子中,我们创建了两个线程。第一个使用匿名类创建,第二个使用lambda表达式创建。两者都使用Runnable接口来创建线程实例。

package com.tutorialspoint;

public class Tester {
   public static void main(String args[]) {
      // create anonymous inner class object
      new Thread(new Runnable() {
         @Override public void run() {
            System.out.println("Thread 1 is running");
         }
      }).start();

      // lambda expression to create the object
      new Thread(() -> {
         System.out.println("Thread 2 is running.");
      }).start();   
   }
}

让我们编译并运行上面的程序,这将产生以下结果:

Thread 1 is running
Thread 2 is running.
广告