Java 函数式接口(Functional Interface)
一、理论说明
1. 函数式接口的定义
Java 函数式接口是一种特殊的接口,它只包含一个抽象方法(Single Abstract Method, SAM),但可以包含多个默认方法或静态方法。函数式接口是 Java 8 引入 Lambda 表达式的基础,通过函数式接口可以将行为作为参数传递,实现更简洁、灵活的代码。
2. 核心特性
- @FunctionalInterface 注解:可选注解,用于标记接口为函数式接口,编译器会检查该接口是否只有一个抽象方法。
- 与 Lambda 表达式的关系:Lambda 表达式是函数式接口的实例,可直接赋值给函数式接口类型的变量。
- 内置函数式接口:Java 8 在
java.util.function
包中提供了一系列通用的函数式接口,如Predicate
、Function
、Consumer
等。
二、内置函数式接口
Java 8 提供了四大核心函数式接口,覆盖了常见的函数式编程场景:
1. Predicate<T>
接收一个参数,返回布尔值,用于判断条件。
@FunctionalInterface
public interface Predicate<T> {boolean test(T t);
}// 使用示例
Predicate<Integer> isEven = num -> num % 2 == 0;
System.out.println(isEven.test(4)); // 输出: true
2. Function<T, R>
接收一个参数,返回另一个类型的结果,用于类型转换。
@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}// 使用示例
Function<String, Integer> strLength = s -> s.length();
System.out.println(strLength.apply("hello")); // 输出: 5
3. Consumer<T>
接收一个参数,不返回结果,用于消费数据。
@FunctionalInterface
public interface Consumer<T> {void accept(T t);
}// 使用示例
Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello, World!"); // 输出: Hello, World!
4. Supplier<T>
不接收参数,返回一个结果,用于提供数据。
@FunctionalInterface
public interface Supplier<T> {T get();
}// 使用示例
Supplier<Double> randomSupplier = () -> Math.random();
System.out.println(randomSupplier.get()); // 输出随机数
三、自定义函数式接口
可以通过 @FunctionalInterface
注解定义自己的函数式接口:
@FunctionalInterface
public interface Calculator {int calculate(int a, int b); // 唯一的抽象方法// 默认方法(非抽象)default void printResult(int result) {System.out.println("计算结果: " + result);}
}// 使用 Lambda 表达式实现
Calculator adder = (a, b) -> a + b;
Calculator subtractor = (a, b) -> a - b;System.out.println(adder.calculate(5, 3)); // 输出: 8
adder.printResult(10); // 输出: 计算结果: 10
四、方法引用(Method Reference)
方法引用是 Lambda 表达式的一种简化形式,用于直接引用已存在的方法。
1. 静态方法引用
// Lambda 表达式
Function<String, Integer> parseInt = s -> Integer.parseInt(s);// 方法引用
Function<String, Integer> parseIntRef = Integer::parseInt;
2. 实例方法引用
// Lambda 表达式
Consumer<String> printer = s -> System.out.println(s);// 方法引用
Consumer<String> printerRef = System.out::println;
3. 构造方法引用
// Lambda 表达式
Supplier<List<String>> listSupplier = () -> new ArrayList<>();// 方法引用
Supplier<List<String>> listSupplierRef = ArrayList::new;
五、应用实例
1. 集合过滤(Predicate)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class FilterExample {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);// 过滤偶数List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0) // 使用 Predicate.collect(Collectors.toList());System.out.println(evenNumbers); // 输出: [2, 4, 6]}
}
2. 数据转换(Function)
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class MapExample {public static void main(String[] args) {List<String> words = Arrays.asList("hello", "world");// 转换为大写List<String> upperCaseWords = words.stream().map(String::toUpperCase) // 使用 Function.collect(Collectors.toList());System.out.println(upperCaseWords); // 输出: [HELLO, WORLD]}
}
3. 事件处理
@FunctionalInterface
public interface ClickListener {void onClick(String event);
}public class Button {private ClickListener listener;public void setOnClickListener(ClickListener listener) {this.listener = listener;}public void simulateClick() {if (listener != null) {listener.onClick("Button clicked");}}
}// 使用 Lambda 表达式处理事件
Button button = new Button();
button.setOnClickListener(event -> System.out.println("处理事件: " + event));
button.simulateClick(); // 输出: 处理事件: Button clicked
六、面试题
题目:
答案:
七、自我总结
函数式接口是 Java 函数式编程的核心,它结合 Lambda 表达式和方法引用,使代码更简洁、更具表现力。关键要点包括:
- 定义规则:函数式接口只能有一个抽象方法,但可以包含默认方法和静态方法。
- 内置接口:
Predicate
、Function
、Consumer
和Supplier
覆盖了常见场景。 - 方法引用:简化 Lambda 表达式,提高代码可读性。
- 与 Stream API 结合:在集合处理中发挥强大作用。
在实际开发中,函数式接口常用于回调、事件处理、集合操作等场景,能够有效减少样板代码,提升开发效率。但需注意避免过度使用复杂的 Lambda 表达式,保持代码的可维护性。