Java函数式接口
函数式接口概览
函数式接口是一种特殊类型的接口,它只有一个抽象方法,因此可以实现函数作为一等公民(first-class functions),即函数可以像任何其他对象一样被传递和操作。
基本概念
- 只有一个抽象方法的接口:这是函数式接口的基本定义。除了这个抽象方法,函数式接口可以有多个默认方法或静态方法。
- @FunctionalInterface 注解:这是一个元注解,用于明确标识一个接口是函数式接口。虽然这个注解不是必需的,但它有两个用途:一是提供编译时检查,确保接口只有一个抽象方法;二是作为一种文档说明,表明该接口是设计为函数式接口的。
- Lambda 表达式:Lambda 表达式是一种简洁的方式来实现函数式接口的匿名实现。Lambda 允许你以更简洁的形式表达单方法接口的实现。
- 方法引用:方法引用是一种使用现有方法作为Lambda表达式的语法糖。它允许你引用类的方法或者构造函数,而不是显式地实现整个函数式接口。
- 构造函数引用:与方法引用类似,构造函数引用允许你引用一个类的构造函数。
- 泛型函数式接口:Java 8 提供了几个泛型函数式接口,如
Function<T,R>、Predicate<T>、Consumer<T>和Supplier<T>等,它们分别用于代表不同的函数操作,比如函数映射、条件判断、消费操作和供应操作。
Java 8 中的函数式接口
以下是 Java 8 提供的一些核心函数式接口:
Supplier<T>:返回类型为 T 的结果,无参数。Consumer<T>:接受一个参数,执行某种操作,无返回值。Function<T,R>:接受一个类型为 T 的参数,并返回类型为 R 的结果。Predicate<T>:接受一个类型为 T 的参数,并返回一个布尔值。BinaryOperator<T>:接受两个类型为 T 的参数,并返回类型为 T 的结果。UnaryOperator<T>:接受一个类型为 T 的参数,并返回类型为 T 的结果
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
Consumer
基本信息
Consumer 接口是 java.util.function 包的一部分。Consumer 接口的泛型声明如下:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Consumer 接口的目的是执行一个操作,它接受一个输入参数,并返回 void。也就是说,它接受了一个参数,并产生了一些结果,但是它是没有返回值的。accept 方法是 Consumer 接口的唯一抽象方法,它接受一个参数并执行某些操作。
Consumer 的使用
Consumer 接口通常用在需要对集合中的每个元素执行操作的场景中,比如在 forEach 方法中。
示例1:使用 forEach 方法

package org.example;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
}
在这个例子中,我们使用 forEach 方法遍历列表,并为每个元素执行 accept 方法。这里我们创建了一个匿名内部类来实现 Consumer 接口。
示例2:使用 Lambda表达式改写
在函数式编程中,可以使用 lambda 表达式简化代码,因此上述代码还能够写为:
package org.example;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
list.forEach(s -> System.out.println(s));
}
}
这里我们直接提供了一个 lambda 表达式作为参数,它实现了 accept 方法。
示例3:使用 forEach 方法和方法引用
如果我们的方法是接收一个参数,并执行操作,我们就可以使用方法引用:
package org.example;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
list.forEach(System.out::println);
}
}
或者我直接自定义一个方法来更好地体现「接受一个参数,并执行操作」的含义:
package org.example;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void print(String s) {
System.out.println(s);
}
public static void main(String[] args) {
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
list.forEach(Main::print);
}
}
在这个例子中,我们使用方法引用 Main::print 来引用 print 方法,它接受一个 String 参数并打印它。
andThen 方法
andThen 是 Consumer 接口提供的一个默认方法,它允许你将两个 Consumer 组合在一起,以便在同一个元素上顺序执行两个操作。这个方法的声明如下:
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
andThen 方法的工作原理
当你调用 andThen 方法时,你需要提供一个 Consumer 对象作为参数。andThen 方法会返回一个新的 Consumer 对象,这个新对象在它的 accept 方法中会先调用当前 Consumer 的 accept 方法,然后调用传入的 Consumer 对象的 accept 方法。
andThen 方法的使用示例
假设我们有两个 Consumer 对象,一个用于打印字符串,另一个用于将字符串转换为大写:
Consumer<String> printConsumer = System.out::println;
Consumer<String> toUpperCaseConsumer = s -> System.out.println(s.toUpperCase());
我们可以使用 andThen 方法将这两个操作组合在一起,使得每个字符串首先被打印,然后它的大写形式也被打印:
Consumer<String> combinedConsumer = printConsumer.andThen(toUpperCaseConsumer);
List<String> list = Arrays.asList("apple", "banana", "cherry");
list.forEach(combinedConsumer);
输出结果将是:
apple
APPLE
banana
BANANA
cherry
CHERRY
在这个例子中,andThen 方法创建了一个新的 Consumer,它将两个操作串联起来。对于列表中的每个元素,都会先执行 printConsumer 的操作(打印字符串),然后执行 toUpperCaseConsumer 的操作(打印字符串的大写形式)。
注意事项
andThen方法返回一个新的Consumer对象,因此它不会修改原始的Consumer对象。- 如果任何一个
Consumer抛出异常,后续的Consumer将不会被执行。 andThen方法可以链式调用,即你可以将多个Consumer组合在一起,例如consumer1.andThen(consumer2).andThen(consumer3)。
Function
Predicate
Supplier
References
- A Deep Dive into Supplier, Consumer, and Function in Java 8. | by Java Fusion | Medium
- Java 8 | Consumer Interface in Java with Examples - GeeksforGeeks
- Java 8 Predicate with Examples - GeeksforGeeks
- Function Interface in Java with Examples - GeeksforGeeks
- Supplier Interface in Java with Examples - GeeksforGeeks
- Method References in Java with examples - GeeksforGeeks
浙公网安备 33010602011771号