在很多函数式语言(如 Kotlin、Scala、JavaScript)里,“高阶函数”指的是:
函数可以作为参数传递,或者作为返回值返回的函数。
而很多 Java 工程师会说:
“Java 又不是函数式语言,哪来的高阶函数?”
其实这是一种表象误解。
1. 从“思想”上看:Java 早就支持高阶函数
看这段线程池代码:
pool.submit(() -> this.loadUser());
你传给submit的是什么?
不是数据
不是配置
而是一段“可执行的行为”
这和函数式语言里的:
submit { loadUser() }
在思想层面完全一致。
你把“怎么做”当成参数传进去了。
2. Java 为什么不用“函数”,而用 Runnable / Callable?
因为 Java 不是用“函数值”,而是用对象来承载行为。
以Callable<T>为例:
@FunctionalInterface public interface Callable<V> { V call() throws Exception; }当你写:
() -> this.loadUser()
编译器会把它自动转换成一个Callable<User>实例。
也就是说:
lambda / 方法引用 ≠ 裸函数
而是:实现了某个“函数式接口”的对象
这就是 Java 的设计取舍。
3. submit 为什么天然就是“高阶函数”?
再看submit的签名:
<T> Future<T> submit(Callable<T> task);
这在函数式语言里的等价表达是:
“submit 接收一个函数 task,并在未来某个时刻调用它,得到结果。”
所以你完全可以这样理解:
submit= 高阶函数Callable/Runnable= 函数参数线程池 = 执行函数的调度器
4. 方法引用只是“语法糖”
pool.submit(this::loadUser);
等价于:
pool.submit(() -> this.loadUser());
只是把:
- “定义一个函数”
- “传入函数”
写得更简洁而已。
5. 为什么 Java 要用“接口”而不是“函数类型”?
这是 Java 的工程取向:
接口有类型系统(可读、可约束)
接口能声明异常(Callable vs Runnable)
接口能作为API 契约
接口能向后兼容
所以 Java 的高阶函数是:
“用接口承载行为,用 lambda 作为实现”
6. 一句话总结
Java 的高阶函数,并不是“函数作为参数”,
而是“把行为封装成函数式接口对象,再作为参数传递”。
Runnable / Callable 本质上就是 Java 里的函数参数。