递归函数必须有明确终止条件,如阶乘需处理n==0和n==1,负数要提前拦截;斐波那契直接递归时间复杂度为o(2^n),应改用记忆化或迭代。

递归函数必须有明确的终止条件
写错递归最常见的情况,就是忘了 return 或者终止条件写成 n == 1 却没处理 n == 0。比如阶乘:如果只写 if (n == 1) return 1;,那传入 0 就会无限调用 factorial(-1)、factorial(-2)…直到栈溢出报 StackOverflowError。
实际写法要覆盖边界值:
public static int factorial(int n) {
if (n
- 负数输入必须提前拦截,否则递归无法收敛
-
n == 0和n == 1建议合并判断,避免逻辑缝隙 - Java 没有尾递归优化,深度太大(比如
n > 10000)仍会爆栈
斐波那契递归别直接照公式硬搬
看到 F(n) = F(n-1) + F(n-2) 就写两行递归?那算 fibonacci(40) 会卡住——因为重复计算爆炸式增长,时间复杂度是 O(2^n),不是线性。
原始写法(不推荐):
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
public static int fibonacci(int n) {
if (n
- 算
fibonacci(5)时,fibonacci(3)被算 2 次,fibonacci(2)被算 3 次 - 到
n == 45左右,耗时就明显可感知;n == 50可能要几秒 - 这不是“递归写错了”,而是没考虑子问题重叠——该上记忆化或换迭代
用 HashMap 做记忆化递归要小心 key 类型和并发
加个缓存就能把斐波那契从指数级拉回 O(n),但 Java 里用 HashMap 存 Integer 键要注意自动装箱陷阱。
正确写法示例:
private static final Map<integer integer> cache = new HashMap();
static {
cache.put(0, 0);
cache.put(1, 1);
}
public static int fibonacci(int n) {
if (n fibonacci(k - 1) + fibonacci(k - 2));
}</integer>
- 别用
new Integer(n)当 key,用基本类型包装类常量池范围外的值会导致==判断失效 - 单线程安全,但多线程下
HashMap不安全;高并发场景得换ConcurrentHashMap -
computeIfAbsent是原子操作,比先containsKey再put更简洁且线程安全(对单个 key)
递归深度超限后别只盯着算法改
当真遇到 StackOverflowError,除了改递归为迭代,还有几个容易被跳过的实操点:
- JVM 默认栈大小通常只有 1MB 左右,可用
-Xss512k或-Xss2m调整,但治标不治本 - IDE 运行时默认参数可能比命令行更保守,检查运行配置里的 VM options
- 某些递归嵌套了大量 lambda 或匿名内部类,会隐式增加栈帧大小,比纯方法调用更早溢出
- Android 上 Dalvik/ART 对栈限制更严,
n > 200的纯递归就可能崩,必须提前降级
递归不是不能用,而是得清楚它在 JVM 上的真实成本——每层调用不只是代码跳转,还带着局部变量表、操作数栈、动态链接这些内存开销。写完跑通只是第一步,压测时栈深度才是临界点。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










