泛型函数式接口需将类型参数声明在接口层级且仅含一个抽象方法,优先复用java.util.function中的标准接口,必要时按业务语义自定义,并避免泛型作用域与推断陷阱。

关键在于把泛型参数声明在接口层级,而不是方法上,并确保接口只有一个抽象方法(SAM)。这样既能享受类型安全,又能让 Lambda 表达式自然适配。
泛型必须定义在接口上
函数式接口的泛型类型参数(如 T 和 R)要写在 interface 声明处,不能放在方法签名里。否则编译器无法保证 SAM 语义,Lambda 也无法正确实现。
- ✅ 正确写法:
@FunctionalInterface public interface Mapper<T, R> { R apply(T t); } - ❌ 错误写法:
public interface Mapper { <T> R apply(T t); }—— 这会让接口变成多抽象方法,失去函数式接口资格
复用 Java 内置泛型函数式接口
大多数场景下无需自己定义,直接使用 java.util.function 包里的标准接口更稳妥、更易理解。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
-
Function<T, R>:输入 T,输出 R,适合转换逻辑(如String::length) -
Predicate<T>:输入 T,返回 boolean,适合条件判断(如Objects::nonNull) -
Supplier<T>:无参,返回 T,适合延迟计算或封装创建逻辑(如() -> new User()) -
Consumer<T>:输入 T,无返回,适合副作用操作(如System.out::println)
按需自定义带业务语义的泛型接口
当通用接口表达力不足时,可以定义有明确业务含义的泛型函数式接口,提升可读性与约束力。
立即学习“Java免费学习笔记(深入)”;
- 例如统一处理「带异常的转换」:
@FunctionalInterface public interface ThrowingMapper<T, R> { R apply(T t) throws IOException; } - 再配合工具方法包装异常:
return () -> mapper.apply(t);,让调用方仍可用 Lambda - 接口名体现意图(如
Validator<T>、Retryer<T>),比裸用Function更利于团队协作
避免常见陷阱
泛型函数式接口容易踩的坑,主要来自类型作用域和推断时机。
- 不要在泛型方法内部构造泛型 Function 变量——它的类型参数会绑定到外层方法,丧失灵活性
- 泛型接口实例化时,尽量让编译器自动推断(如
Function<String, Integer> f = Integer::parseInt;),少写冗余类型 - 若涉及多参数,优先选
BiFunction<T, U, R>等内置接口,而非强行扩展单参数接口

















