繁体   English   中英

Java 与 finally 块和递归的谜语

[英]Java Riddle with finally block and recursion

我刚刚为我们的团队准备了一个关于 java 谜语的游戏。 可以这么说,一小段 java 代码会做一些乍看之下意想不到的事情。

在搜索这些谜语的同时,我还在我的 IDE 中乱涂乱画,并尝试了一些你永远不会在生产代码中编写的奇怪东西。 就是图个好玩儿。

我突然想到了以下几点:

public static int cnt = 0;
public static int blubb() {
    try {
        cnt++;
        return blubb();
    } finally {
        return cnt;
    }
}

public static void main(String[] args) {
    System.out.println(cnt + ": " + Main.blubb() + ": " + cnt);
}

执行时,它会打印类似“0:21245:21245”的内容,其中每次运行的 21245 都不同。

我希望要么无限递归,要么在 finally 块中返回 1 (0: 1: 1)

当添加一个 catch 块来捕获 Throwable 和调试时,调试器将永远不会停止在这个块中。

有人可以解释一下这里发生了什么吗?

像这样添加一个catch块,但没有看到堆栈跟踪,并不表示没有抛出任何东西:

    } catch (Throwable t) {
      t.printStackTrace();
      throw t;
    } finally { ... }

预计在捕获StackOverflowError后无法立即打印StackOverflowError的堆栈跟踪:SOE 字面意思是不能进行更多的方法调用。

但是要调用printStackTrace() ,您需要进行另一个方法调用。 因此,方法调用实际上会导致另一个单独的StackOverflowError ,您不会尝试打印它。 但随后 finally 中的return导致StackOverflowError被丢弃。

试试这个,当StackOverflowError被抛出时不需要方法调用:

import java.util.*;

class Main {
  public static int cnt = 0;

  private static Throwable caught;

  public static int blubb() throws Throwable {
    try {
      cnt++;
      return blubb();
    } catch (Throwable t) {
      caught = t;
      throw t;
    } finally {
      return cnt;
    }
  }

  public static void main(String[] args) throws Throwable {
    System.out.println(cnt + ": " + Main.blubb() + ": " + cnt);
    System.out.println(caught);
  }
}

对我来说,这打印:

0: 9672: 9672
java.lang.StackOverflowError

所以是的,一个StackOverflowError被捕获了。

您创建了一个无限递归循环。

有时调用堆栈变得如此之大,它会引发StackOverflowError并且您的应用程序应该崩溃。

但是您在try块中设置了递归调用。 所以异常被部分处理,而不是因为你没有catch块而被显示。

由于您有一个finally块返回cnt的值,因此堆栈中的许多调用都会返回该值,然后返回19543或在异常之前调用它的任何次数。

TL;DR:使用try块时,不要隐藏异常

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM