1. 函数式接口 (Functional Interface)
函数式接口是指只包含一个抽象方法的接口,这样的接口可以用 lambda 表达式或者方法引用来创建其实例。Java 8 引入了函数式接口的概念,它通常用于传递行为(即函数),使代码更加简洁和灵活。
定义一个函数式接口的基本语法:
@FunctionalInterface
public interface MyFunctionalInterface<T> {
T apply(T t); // 只有一个抽象方法
}
@FunctionalInterface
注解不是强制的,但它有助于确保该接口符合函数式接口的规范(即只有一个抽象方法)。apply
是唯一的抽象方法,它接受一个参数并返回一个值。
2. 使用 Lambda 表达式作为函数式接口的参数
当一个函数式接口的实例作为方法的参数传递时,我们通常使用 lambda 表达式 来传递该实例。lambda 表达式是一种简洁的写法,用来实现函数式接口的 apply
方法(或该接口中定义的其他方法)。
Lambda 表达式的基本语法
(parameter) -> expression
parameter
:参数部分,这里是 lambda 表达式的输入。expression
:表达式部分,lambda 表达式的计算结果。
例如,在你的 MyFunctionalInterface
中使用 lambda 表达式:
MyFunctionalInterface<Integer> square = (x) -> x * x;
这个 lambda 表达式实现了 MyFunctionalInterface
接口的 apply
方法,并且参数类型和返回值类型是 Integer
,因为它是用来计算 x * x
的。
在方法中作为参数使用 lambda 表达式
假设你有一个方法,它接受一个函数式接口作为参数:
public static <T> T processData(T input, MyFunctionalInterface<T> func) {
return func.apply(input);
}
调用时,你可以使用 lambda 表达式传递具体的实现:
Integer result = processData(5, (x) -> x * x); // 输出 25
3. Lambda 表达式的类型匹配
当你使用 lambda 表达式时,唯一需要注意的就是 lambda 表达式的 参数类型和返回值类型必须与函数式接口中的方法类型匹配。这是使用 lambda 表达式时最重要的规则。
参数类型匹配
- 如果函数式接口的方法接受一个参数
T
,那么你传递的 lambda 表达式的参数类型必须与T
相同。
返回值类型匹配
- 如果函数式接口的方法返回类型是
T
,那么你传递的 lambda 表达式必须返回类型T
。
例如,MyFunctionalInterface<Integer>
需要一个接收 Integer
类型并返回 Integer
类型的方法,所以 lambda 表达式应该这样定义:
MyFunctionalInterface<Integer> square = (x) -> x * x; // 返回 Integer 类型
4. 方法引用:与 Lambda 表达式等价
方法引用是 lambda 表达式的一种简写形式,允许我们使用已经存在的方法来替代 lambda 表达式。方法引用可以视为一种特殊的 lambda 表达式,通常用于引用类或对象中的已定义方法。
方法引用的基本语法
ClassName::methodName
例如,你可以用方法引用来替代前面的 lambda 表达式:
MyFunctionalInterface<Integer> square = Integer::parseInt;
方法引用的应用
public static <T> T processData(T input, MyFunctionalInterface<T> func) {
return func.apply(input);
}
你可以通过方法引用来简化:
Integer result = processData(5, x -> x * x); // lambda 表达式
Integer result2 = processData(5, Integer::parseInt); // 方法引用
5. 使用方法引用时不可以传参
方法引用实际上是不允许在引用时直接传递参数的。无论是静态方法、实例方法还是构造方法,方法引用语法都不支持在引用时传入参数。
方法引用的几种基本形式:
- 静态方法引用:
ClassName::staticMethod
- 特定对象的方法引用:
objectRef::instanceMethod
- 特定类型的任意对象的方法引用:
ClassName::instanceMethod
- 构造方法引用:
ClassName::new
这些形式都是不带参数的。如果要传递参数,必须使用Lambda表达式。
比如:
// 错误示例(不允许传参)
Claims::get("username", String.class) // 这是不合法的
// 正确写法
claims -> claims.get("username", String.class) // Lambda表达式
所以很明确地说:方法引用不允许传递任何参数,哪怕是一个参数也不行。要传参数,就必须使用Lambda表达式。
6. 总结
你说的内容是非常正确的,核心要点可以归纳为:
- 函数式接口 是只包含一个抽象方法的接口,可以通过 lambda 表达式或方法引用来实现。
- 使用函数式接口的参数时,通常通过 lambda 表达式 来提供具体的实现,lambda 表达式的参数和返回值类型必须与接口方法的参数和返回值类型匹配。
- 方法引用 可以作为 lambda 表达式的简写,它等价于 lambda 表达式,但需要确保:
- 方法引用的 参数类型 与函数式接口的方法 参数类型 匹配。
- 方法引用的 返回值类型 与函数式接口的方法 返回值类型 匹配。