写在前面
欢迎来到JDK8新特性系列教程的第二天!在昨天的学习中,我们了解了Lambda表达式的基本概念和用法。今天,我们将深入探讨Lambda表达式的"灵魂伴侣"------函数式接口。
如果说Lambda表达式是JDK8送给Java程序员的"语法糖",那么函数式接口就是承载这颗糖的"容器"。理解函数式接口,是掌握Java函数式编程的关键一步。
准备好了吗?让我们开始今天的学习之旅!

目录
-
- 写在前面
- 一、什么是函数式接口
-
- [1.1 定义](#1.1 定义)
- [1.2 @FunctionalInterface注解](#1.2 @FunctionalInterface注解)
- [1.3 函数式接口 vs 普通接口](#1.3 函数式接口 vs 普通接口)
- 二、四大核心函数式接口详解
-
- [2.1 Function<T, R> - 函数型接口](#2.1 Function<T, R> - 函数型接口)
- [2.2 Consumer<T> - 消费型接口](#2.2 Consumer<T> - 消费型接口)
- [2.3 Supplier<T> - 供给型接口](#2.3 Supplier<T> - 供给型接口)
- [2.4 Predicate<T> - 断言型接口](#2.4 Predicate<T> - 断言型接口)
- [2.5 四大核心接口对比表](#2.5 四大核心接口对比表)
- 三、其他常用函数式接口
-
- [3.1 UnaryOperator<T> - 一元操作符](#3.1 UnaryOperator<T> - 一元操作符)
- [3.2 BinaryOperator<T> - 二元操作符](#3.2 BinaryOperator<T> - 二元操作符)
- [3.3 BiFunction<T, U, R> - 双参数函数](#3.3 BiFunction<T, U, R> - 双参数函数)
- [3.4 BiConsumer<T, U> - 双参数消费者](#3.4 BiConsumer<T, U> - 双参数消费者)
- [3.5 BiPredicate<T, U> - 双参数断言](#3.5 BiPredicate<T, U> - 双参数断言)
- [3.6 基本类型特化接口](#3.6 基本类型特化接口)
- 四、函数式接口的链式操作
-
- [4.1 Function的链式操作](#4.1 Function的链式操作)
- [4.2 Consumer的链式操作](#4.2 Consumer的链式操作)
- [4.3 Predicate的链式操作](#4.3 Predicate的链式操作)
- [4.4 链式操作对比表](#4.4 链式操作对比表)
- 五、自定义函数式接口
-
- [5.1 基本自定义](#5.1 基本自定义)
- [5.2 带泛型的自定义接口](#5.2 带泛型的自定义接口)
- [5.3 带异常的函数式接口](#5.3 带异常的函数式接口)
- 六、踩坑提醒
-
- [6.1 函数式接口只能有一个抽象方法](#6.1 函数式接口只能有一个抽象方法)
- [6.2 Object类方法的陷阱](#6.2 Object类方法的陷阱)
- [6.3 Lambda表达式类型推断问题](#6.3 Lambda表达式类型推断问题)
- [6.4 变量捕获的限制](#6.4 变量捕获的限制)
- 七、面试高频考点
-
- [7.1 函数式接口和抽象类的区别?](#7.1 函数式接口和抽象类的区别?)
- [7.2 JDK8提供了哪些内置函数式接口?](#7.2 JDK8提供了哪些内置函数式接口?)
- [7.3 @FunctionalInterface注解的作用?](#7.3 @FunctionalInterface注解的作用?)
- [7.4 为什么Lambda表达式只能用于函数式接口?](#7.4 为什么Lambda表达式只能用于函数式接口?)
- 八、总结
- 参考资料
- 互动话题
一、什么是函数式接口
1.1 定义
函数式接口(Functional Interface)是指有且仅有一个抽象方法的接口。这种接口可以被隐式转换为Lambda表达式。
1.2 @FunctionalInterface注解
JDK8引入了@FunctionalInterface注解,用于标识一个接口是函数式接口:
java
@FunctionalInterface
public interface MyFunctionalInterface {
// 只有一个抽象方法
void execute();
// 默认方法可以有多个,不算抽象方法
default void defaultMethod() {
System.out.println("这是默认方法");
}
// 静态方法可以有多个,不算抽象方法
static void staticMethod() {
System.out.println("这是静态方法");
}
}
重要提示 :@FunctionalInterface注解不是必须的,但强烈建议使用。因为它可以帮助编译器检查接口是否符合函数式接口的定义------如果接口中有多个抽象方法,编译器会报错。
1.3 函数式接口 vs 普通接口
| 特性 | 函数式接口 | 普通接口 |
|---|---|---|
| 抽象方法数量 | 有且仅有1个 | 可以有多个 |
| 默认方法 | 可以有 | 可以有 |
| 静态方法 | 可以有 | 可以有 |
| 能否使用Lambda | 可以 | 不可以 |
| 注解标识 | 建议使用@FunctionalInterface | 不需要 |
二、四大核心函数式接口详解
JDK8在java.util.function包中提供了大量内置的函数式接口,其中最核心的是以下四个:
2.1 Function<T, R> - 函数型接口
定义:接收一个参数T,返回一个结果R。
java
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
应用场景:类型转换、数据映射、提取属性等。
java
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
// 将字符串转换为长度
Function<String, Integer> lengthFunction = s -> s.length();
System.out.println(lengthFunction.apply("Hello")); // 输出: 5
System.out.println(lengthFunction.apply("Java8")); // 输出: 5
// 将整数转换为字符串
Function<Integer, String> intToString = i -> "Number: " + i;
System.out.println(intToString.apply(100)); // 输出: Number: 100
// 复杂示例:字符串处理管道
Function<String, String> trim = String::trim;
Function<String, String> toUpperCase = String::toUpperCase;
Function<String, String> addPrefix = s -> "[PROCESSED] " + s;
String result = trim.andThen(toUpperCase).andThen(addPrefix).apply(" hello world ");
System.out.println(result); // 输出: [PROCESSED] HELLO WORLD
}
}
2.2 Consumer - 消费型接口
定义:接收一个参数T,不返回任何结果(返回void)。
java
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
应用场景:打印日志、发送消息、修改对象状态等副作用操作。
java
import java.util.function.Consumer;
import java.util.Arrays;
import java.util.List;
public class ConsumerDemo {
public static void main(String[] args) {
// 简单的打印消费者
Consumer<String> printConsumer = s -> System.out.println(s);
printConsumer.accept("Hello Consumer!");
// 对象处理消费者
Consumer<List<Integer>> clearList = list -> list.clear();
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 注意:Arrays.asList返回的列表不能修改,这里仅作示例
// 实际应用:遍历集合并处理
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Consumer<String> greet = name -> System.out.println("Hello, " + name + "!");
names.forEach(greet);
// 输出:
// Hello, Alice!
// Hello, Bob!
// Hello, Charlie!
// 多个消费者的组合
Consumer<String> printUpper = s -> System.out.println(s.toUpperCase());
Consumer<String> printLength = s -> System.out.println("Length: " + s.length());
Consumer<String> combined = printUpper.andThen(printLength);
combined.accept("Java");
// 输出:
// JAVA
// Length: 4
}
}
2.3 Supplier - 供给型接口
定义:不接收任何参数,返回一个结果T。
java
@FunctionalInterface
public interface Supplier<T> {
T get();
}
应用场景:延迟加载、工厂模式、生成数据等。
java
import java.util.function.Supplier;
import java.util.Random;
public class SupplierDemo {
public static void main(String[] args) {
// 生成随机数
Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);
System.out.println(randomSupplier.get()); // 输出: 0-99之间的随机数
System.out.println(randomSupplier.get()); // 输出: 另一个随机数
// 延迟创建对象
Supplier<StringBuilder> sbSupplier = StringBuilder::new;
StringBuilder sb = sbSupplier.get();
sb.append("Hello").append(" ").append("World");
System.out.println(sb.toString()); // 输出: Hello World
// 实际应用:Optional的orElseGet
String value = null;
String result = java.util.Optional.ofNullable(value)
.orElseGet(() -> "Default Value");
System.out.println(result); // 输出: Default Value
// 工厂模式应用
Supplier<Person> personFactory = () -> new Person("Unknown", 0);
Person person = personFactory.get();
System.out.println(person);
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
2.4 Predicate - 断言型接口
定义:接收一个参数T,返回boolean结果。
java
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
应用场景:条件判断、过滤数据、验证输入等。
java
import java.util.function.Predicate;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class PredicateDemo {
public static void main(String[] args) {
// 基本用法
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // 输出: true
System.out.println(isEven.test(5)); // 输出: false
// 字符串判断
Predicate<String> isNotEmpty = s -> s != null && !s.isEmpty();
System.out.println(isNotEmpty.test("Hello")); // 输出: true
System.out.println(isNotEmpty.test("")); // 输出: false
// 实际应用:过滤集合
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbers = numbers.stream()
.filter(isEven)
.collect(Collectors.toList());
System.out.println(evenNumbers); // 输出: [2, 4, 6, 8, 10]
// 组合多个条件
Predicate<Integer> greaterThan5 = n -> n > 5;
Predicate<Integer> lessThan10 = n -> n < 10;
// 与操作
Predicate<Integer> between5And10 = greaterThan5.and(lessThan10);
System.out.println(between5And10.test(7)); // 输出: true
System.out.println(between5And10.test(11)); // 输出: false
// 或操作
Predicate<Integer> lessThan3OrGreaterThan8 =
((Predicate<Integer>) n -> n < 3).or(n -> n > 8);
System.out.println(lessThan3OrGreaterThan8.test(2)); // 输出: true
System.out.println(lessThan3OrGreaterThan8.test(5)); // 输出: false
System.out.println(lessThan3OrGreaterThan8.test(9)); // 输出: true
}
}
2.5 四大核心接口对比表
| 接口名 | 方法签名 | 输入 | 输出 | 典型用途 |
|---|---|---|---|---|
| Function<T,R> | R apply(T t) | T | R | 类型转换、数据映射 |
| Consumer | void accept(T t) | T | void | 副作用操作、处理数据 |
| Supplier | T get() | 无 | T | 延迟加载、数据生成 |
| Predicate | boolean test(T t) | T | boolean | 条件判断、数据过滤 |
三、其他常用函数式接口
除了四大核心接口,JDK8还提供了许多其他实用的函数式接口:
3.1 UnaryOperator - 一元操作符
UnaryOperator<T>是Function<T, T>的特化,输入和输出类型相同。
java
import java.util.function.UnaryOperator;
public class UnaryOperatorDemo {
public static void main(String[] args) {
// 字符串转大写
UnaryOperator<String> toUpperCase = s -> s.toUpperCase();
System.out.println(toUpperCase.apply("hello")); // 输出: HELLO
// 数字平方
UnaryOperator<Integer> square = n -> n * n;
System.out.println(square.apply(5)); // 输出: 25
// List的replaceAll使用UnaryOperator
java.util.List<String> list = new java.util.ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.replaceAll(s -> s.toUpperCase());
System.out.println(list); // 输出: [A, B, C]
}
}
3.2 BinaryOperator - 二元操作符
BinaryOperator<T>是BiFunction<T, T, T>的特化,两个输入和一个输出类型相同。
java
import java.util.function.BinaryOperator;
public class BinaryOperatorDemo {
public static void main(String[] args) {
// 两数相加
BinaryOperator<Integer> add = (a, b) -> a + b;
System.out.println(add.apply(3, 5)); // 输出: 8
// 字符串拼接
BinaryOperator<String> concat = (s1, s2) -> s1 + " " + s2;
System.out.println(concat.apply("Hello", "World")); // 输出: Hello World
// 求最大值
BinaryOperator<Integer> max = BinaryOperator.maxBy(Integer::compare);
System.out.println(max.apply(10, 20)); // 输出: 20
// 求最小值
BinaryOperator<Integer> min = BinaryOperator.minBy(Integer::compare);
System.out.println(min.apply(10, 20)); // 输出: 10
}
}
3.3 BiFunction<T, U, R> - 双参数函数
接收两个不同类型参数,返回一个结果。
java
import java.util.function.BiFunction;
public class BiFunctionDemo {
public static void main(String[] args) {
// 拼接字符串和数字
BiFunction<String, Integer, String> format =
(prefix, number) -> prefix + ": " + number;
System.out.println(format.apply("Score", 95)); // 输出: Score: 95
// 创建对象
BiFunction<String, Integer, Person> createPerson = Person::new;
Person person = createPerson.apply("Alice", 25);
System.out.println(person); // 输出: Person{name='Alice', age=25}
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
3.4 BiConsumer<T, U> - 双参数消费者
接收两个参数,不返回结果。
java
import java.util.function.BiConsumer;
import java.util.Map;
import java.util.HashMap;
public class BiConsumerDemo {
public static void main(String[] args) {
// 打印键值对
BiConsumer<String, Integer> printEntry = (key, value) ->
System.out.println(key + " = " + value);
printEntry.accept("Age", 25); // 输出: Age = 25
// 遍历Map
Map<String, Integer> scores = new HashMap<>();
scores.put("Math", 95);
scores.put("English", 88);
scores.put("Science", 92);
scores.forEach((subject, score) ->
System.out.println(subject + ": " + score + "分")
);
}
}
3.5 BiPredicate<T, U> - 双参数断言
接收两个参数,返回boolean。
java
import java.util.function.BiPredicate;
public class BiPredicateDemo {
public static void main(String[] args) {
// 判断字符串长度是否等于指定值
BiPredicate<String, Integer> lengthEquals =
(str, len) -> str.length() == len;
System.out.println(lengthEquals.test("Hello", 5)); // 输出: true
System.out.println(lengthEquals.test("Hello", 4)); // 输出: false
// 判断数字是否在范围内
BiPredicate<Integer, int[]> inRange = (num, range) ->
num >= range[0] && num <= range[1];
System.out.println(inRange.test(5, new int[]{1, 10})); // 输出: true
}
}
3.6 基本类型特化接口
为了避免装箱拆箱的性能开销,JDK8为基本类型提供了特化版本:
| 接口类型 | int特化 | long特化 | double特化 |
|---|---|---|---|
| Function | IntFunction | LongFunction | DoubleFunction |
| Consumer | IntConsumer | LongConsumer | DoubleConsumer |
| Supplier | IntSupplier | LongSupplier | DoubleSupplier |
| Predicate | IntPredicate | LongPredicate | DoublePredicate |
| UnaryOperator | IntUnaryOperator | LongUnaryOperator | DoubleUnaryOperator |
| BinaryOperator | IntBinaryOperator | LongBinaryOperator | DoubleBinaryOperator |
java
import java.util.function.IntPredicate;
import java.util.function.IntFunction;
public class PrimitiveDemo {
public static void main(String[] args) {
// 使用int特化避免装箱
IntPredicate isPositive = n -> n > 0;
System.out.println(isPositive.test(5)); // 输出: true
System.out.println(isPositive.test(-3)); // 输出: false
IntFunction<String> intToString = n -> "Number: " + n;
System.out.println(intToString.apply(42)); // 输出: Number: 42
// 性能对比:使用特化版本比Predicate<Integer>更高效
}
}
四、函数式接口的链式操作
函数式接口支持链式调用,可以组合多个操作形成复杂的数据处理管道。
4.1 Function的链式操作
java
import java.util.function.Function;
public class FunctionChaining {
public static void main(String[] args) {
Function<String, String> trim = String::trim;
Function<String, String> toLowerCase = String::toLowerCase;
Function<String, Integer> length = String::length;
// andThen: 先执行当前函数,再执行参数函数
String result1 = trim.andThen(toLowerCase).apply(" HELLO WORLD ");
System.out.println(result1); // 输出: hello world
// compose: 先执行参数函数,再执行当前函数
String result2 = toLowerCase.compose(trim).apply(" HELLO WORLD ");
System.out.println(result2); // 输出: hello world
// 链式获取长度
Integer len = trim.andThen(toLowerCase).andThen(length).apply(" HELLO ");
System.out.println(len); // 输出: 5
// identity: 返回输入本身
Function<String, String> identity = Function.identity();
System.out.println(identity.apply("test")); // 输出: test
}
}
4.2 Consumer的链式操作
java
import java.util.function.Consumer;
public class ConsumerChaining {
public static void main(String[] args) {
Consumer<String> print = s -> System.out.println("Print: " + s);
Consumer<String> log = s -> System.out.println("Log: " + s);
Consumer<String> save = s -> System.out.println("Save: " + s);
// andThen: 依次执行多个消费者
Consumer<String> combined = print.andThen(log).andThen(save);
combined.accept("Hello");
// 输出:
// Print: Hello
// Log: Hello
// Save: Hello
}
}
4.3 Predicate的链式操作
java
import java.util.function.Predicate;
import java.util.List;
import java.util.Arrays;
import java.util.stream.Collectors;
public class PredicateChaining {
public static void main(String[] args) {
Predicate<Integer> greaterThan5 = n -> n > 5;
Predicate<Integer> lessThan20 = n -> n < 20;
Predicate<Integer> isEven = n -> n % 2 == 0;
// and: 逻辑与
Predicate<Integer> between5And20 = greaterThan5.and(lessThan20);
// or: 逻辑或
Predicate<Integer> lessThan5OrEven = lessThan20.negate().or(isEven);
// negate: 逻辑非
Predicate<Integer> notEven = isEven.negate();
// 复杂组合
Predicate<Integer> complex = greaterThan5
.and(lessThan20)
.and(isEven);
List<Integer> numbers = Arrays.asList(1, 6, 8, 12, 15, 22, 24);
List<Integer> filtered = numbers.stream()
.filter(complex)
.collect(Collectors.toList());
System.out.println(filtered); // 输出: [6, 8, 12]
// isEqual: 静态方法,判断是否等于指定值
Predicate<String> isJava = Predicate.isEqual("Java");
System.out.println(isJava.test("Java")); // 输出: true
System.out.println(isJava.test("Python")); // 输出: false
}
}
4.4 链式操作对比表
| 接口 | 方法 | 作用 | 示例 |
|---|---|---|---|
| Function | andThen | 先执行当前,再执行参数 | f.andThen(g).apply(x) = g(f(x)) |
| Function | compose | 先执行参数,再执行当前 | f.compose(g).apply(x) = f(g(x)) |
| Function | identity | 返回输入本身 | Function.identity().apply(x) = x |
| Consumer | andThen | 依次执行多个消费者 | c1.andThen(c2).accept(x) |
| Predicate | and | 逻辑与 | p1.and(p2).test(x) |
| Predicate | or | 逻辑或 | p1.or(p2).test(x) |
| Predicate | negate | 逻辑非 | p.negate().test(x) |
| Predicate | isEqual | 判断是否相等 | Predicate.isEqual(obj) |
五、自定义函数式接口
虽然JDK8提供了丰富的内置函数式接口,但在某些场景下,我们仍需要自定义函数式接口。
5.1 基本自定义
java
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}
// 使用
public class CustomFunctionalInterface {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b;
Calculator subtract = (a, b) -> a - b;
Calculator multiply = (a, b) -> a * b;
System.out.println(add.calculate(5, 3)); // 输出: 8
System.out.println(subtract.calculate(5, 3)); // 输出: 2
System.out.println(multiply.calculate(5, 3)); // 输出: 15
}
}
5.2 带泛型的自定义接口
java
@FunctionalInterface
public interface Validator<T> {
boolean validate(T value);
// 默认方法提供组合功能
default Validator<T> and(Validator<T> other) {
return value -> this.validate(value) && other.validate(value);
}
default Validator<T> or(Validator<T> other) {
return value -> this.validate(value) || other.validate(value);
}
}
// 使用
public class ValidatorDemo {
public static void main(String[] args) {
Validator<String> notNull = s -> s != null;
Validator<String> notEmpty = s -> !s.isEmpty();
Validator<String> minLength3 = s -> s.length() >= 3;
Validator<String> validName = notNull.and(notEmpty).and(minLength3);
System.out.println(validName.validate("John")); // 输出: true
System.out.println(validName.validate("Jo")); // 输出: false
System.out.println(validName.validate("")); // 输出: false
System.out.println(validName.validate(null)); // 输出: false
}
}
5.3 带异常的函数式接口
JDK8的函数式接口不允许抛出受检异常,需要自定义:
java
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
}
// 包装工具类
public class LambdaExceptionUtil {
public static <T, R, E extends Exception> Function<T, R>
wrap(ThrowingFunction<T, R, E> throwingFunction) {
return t -> {
try {
return throwingFunction.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
// 使用
public class ExceptionDemo {
public static void main(String[] args) {
java.util.List<String> list = java.util.Arrays.asList("1", "2", "abc");
// 使用包装后的函数处理可能抛出异常的代码
list.stream()
.map(LambdaExceptionUtil.wrap(Integer::parseInt))
.forEach(System.out::println);
}
}
六、踩坑提醒
6.1 函数式接口只能有一个抽象方法
坑点:默认方法和静态方法不算抽象方法,但如果接口继承了其他接口的方法,可能导致抽象方法数量超过1个。
java
// 错误示例
@FunctionalInterface
public interface BadInterface extends Runnable {
void run(); // 来自Runnable的抽象方法
void doSomething(); // 另一个抽象方法 - 编译错误!
}
// 正确示例
@FunctionalInterface
public interface GoodInterface extends Runnable {
// 只继承run(),没有新增抽象方法
default void doSomething() {
System.out.println("Doing something");
}
}
6.2 Object类方法的陷阱
如果函数式接口声明了Object类中的方法(如equals、toString、hashCode),这些方法不算作抽象方法:
java
@FunctionalInterface
public interface MyInterface {
void execute(); // 唯一的抽象方法
// 以下方法不会导致编译错误
boolean equals(Object obj); // Object类的方法
String toString(); // Object类的方法
int hashCode(); // Object类的方法
}
6.3 Lambda表达式类型推断问题
java
import java.util.function.Function;
import java.util.function.BiFunction;
public class TypeInferencePitfall {
public static void main(String[] args) {
// 编译错误:类型推断失败
// var func = (String s) -> s.length();
// 正确做法:显式声明类型
Function<String, Integer> func = s -> s.length();
// 或者使用类型推断(省略参数类型)
Function<String, Integer> func2 = (s) -> s.length();
// 注意:只有一个参数时括号可以省略
Function<String, Integer> func3 = s -> s.length();
}
}
6.4 变量捕获的限制
Lambda表达式只能捕获final或 effectively final 的局部变量:
java
public class VariableCapture {
public static void main(String[] args) {
int count = 0;
// 编译错误:count必须是final或effectively final
// Runnable r = () -> System.out.println(count++);
// 正确做法:使用数组或原子类包装
int[] counter = {0};
Runnable r = () -> System.out.println(counter[0]++);
r.run(); // 输出: 0
r.run(); // 输出: 1
// 更好的做法:使用原子类
java.util.concurrent.atomic.AtomicInteger atomicCount =
new java.util.concurrent.atomic.AtomicInteger(0);
Runnable r2 = () -> System.out.println(atomicCount.getAndIncrement());
r2.run(); // 输出: 0
r2.run(); // 输出: 1
}
}
七、面试高频考点
7.1 函数式接口和抽象类的区别?
| 特性 | 函数式接口 | 抽象类 |
|---|---|---|
| 继承 | 可以多实现 | 只能单继承 |
| 方法 | 只能有1个抽象方法 | 可以有多个抽象方法 |
| 状态 | 不能有实例字段 | 可以有实例字段 |
| 构造器 | 没有 | 有 |
| 访问修饰符 | 默认public | 可以自定义 |
| 使用场景 | 行为参数化 | 代码复用、模板方法 |
7.2 JDK8提供了哪些内置函数式接口?
JDK8在java.util.function包中提供了43个函数式接口,主要包括:
核心接口(4个):
- Function<T,R>:类型转换
- Consumer:消费数据
- Supplier:提供数据
- Predicate:条件判断
扩展接口:
- UnaryOperator:一元操作
- BinaryOperator:二元操作
- BiFunction<T,U,R>:双参数函数
- BiConsumer<T,U>:双参数消费者
- BiPredicate<T,U>:双参数断言
基本类型特化(约30+个):
- IntFunction、LongFunction、DoubleFunction
- IntConsumer、LongConsumer、DoubleConsumer
- IntPredicate、LongPredicate、DoublePredicate
- 等等...
7.3 @FunctionalInterface注解的作用?
- 标识作用:明确表示这是一个函数式接口
- 编译检查:编译器会检查接口是否只有一个抽象方法
- 文档说明:帮助其他开发者理解接口的设计意图
- 生成文档:在Javadoc中生成特殊标记
7.4 为什么Lambda表达式只能用于函数式接口?
Lambda表达式的本质是匿名函数,它没有名称、没有类型,只有参数列表和方法体。函数式接口只有一个抽象方法,因此Lambda表达式可以明确地对应该方法。如果接口有多个抽象方法,编译器就无法确定Lambda表达式对应哪个方法。
八、总结
今天我们深入学习了JDK8的函数式接口,主要内容包括:
- 函数式接口的定义:有且仅有一个抽象方法的接口
- 四大核心接口:Function、Consumer、Supplier、Predicate
- 其他常用接口:UnaryOperator、BinaryOperator、BiFunction等
- 链式操作:andThen、compose、and、or、negate等方法的使用
- 自定义函数式接口:满足特定业务需求
- 常见坑点:抽象方法数量限制、变量捕获限制等
下一步预告
在Day3中,我们将学习方法引用与构造器引用,这是Lambda表达式的语法糖,能让代码更加简洁优雅。我们将探讨:
- 方法引用的四种类型
- 方法引用与Lambda的区别
- 构造器引用的使用场景
敬请期待!
参考资料
互动话题
- 你在实际项目中使用过哪些函数式接口?遇到过什么坑吗?
- 你觉得函数式编程给Java带来了哪些改变?
- 对于自定义函数式接口,你有什么好的设计经验分享?
欢迎在评论区留言讨论,点赞收藏不迷路,我们Day3见!