【问题标题】:why is it not possible to insert code between try and catch block?为什么不能在 try 和 catch 块之间插入代码?
【发布时间】:2026-01-21 14:45:01
【问题描述】:

我在面试中被问到如果我们将 finally 块放在 try 和 catch 块之间会发生什么我回答在这种情况下编译器会认为没有 catch 块,它将直接执行 finally 块。 然后他问为什么不能在try和catch块之间放代码?

你能帮帮我吗...

【问题讨论】:

  • 您对第一个问题的回答是错误的。编译器不会认为没有catch 块。它显然仍然存在于您的代码中,并且它紧跟在 finally 块之后的事实将导致编译时错误。
  • BoltClock 是正确的 - 您在第一个问题上遇到编译器错误。 catch 必须紧跟在 try 之前
  • catch 块在语法上必须紧跟在 try 块之后。没有其他原因。

标签: java try-catch


【解决方案1】:

好的,首先 - 编译器执行代码,它只是编译它,允许它由 JVM 运行。

从经验上讲,这并没有多大意义,因为如果您有一些代码想要放在 try 块之外但在 catch 块之前,那么这些代码也可以放在 try 块中。问题是,如果你仔细想想,它的行为就像在 try 块中一样。

让我们假设这是有效的Java(这不会编译):

try {
    throw new Exception();
}
System.out.println("Sup!");
catch(Exception e) { }

当异常被抛出时,打印出Sup! 的那行仍将被跳过,因为 JVM 正在搜索跳转到适当的异常处理程序以处理 Exception。因此,在某种程度上,代码的行为就像它在 try {} 块本身中一样,这就是为什么它在哪里并不重要,并且 Java 指定 this (现在被证明是无用的) 构造是非法的。

如果尝试后的代码本身抛出另一个异常怎么办?如果它是有效代码,它的行为就像原始 try 块中的嵌套 try...catch 块一样。当然,一旦事情开始变得复杂,在 try 和 catch 块之间没有明确联系的方法可能会变得模糊,并且 JVM 最终会不知道哪个 catch/finally 属于哪个 try 块(特别是因为处理程序不必在同一个函数中,甚至在同一个包中!)。

【讨论】:

  • 谢谢!添加了一些小东西(尤其是关于我的小 Java sn-p 错误的更清晰的陈述)
  • 请注意,在 JVM 级别,不要求嵌套 try 块。您可以拥有foo(); bar(); baz();,同时拥有foo()baz() 捕获异常并跳转到same 捕获代码,而bar() 则转到不同的捕获代码。所发生的只是有一个表格显示哪些字节码范围进入了哪些 catch 处理程序;编译器可以按照它喜欢的任何方式设置这个表。因此,尽管这种构造可能会混淆javac,但 JVM 很乐意实现您为其定义的任何语义。
【解决方案2】:

嗯,轻率的答案是语言规范禁止它。

但让我们退后一步,换个角度想一想——如果你可以这样做呢?

try {
  foo();
}
bar();
catch (Exception e) {
  baz();
}

这可能是什么语义?如果我们在foo() 中捕获异常,是否会调用baz()bar() 呢?如果bar() 抛出,我们会在这种情况下捕获异常吗?

如果bar() 中的异常没有被捕获,并且foo() 中的异常阻止bar() 运行,则该构造相当于:

try {
  foo();
} catch (Exception e) {
  baz();
}
bar();

如果bar() 中的异常捕获,而foo() 中的异常阻止bar() 运行,则构造等效于:

try {
  foo();
  bar();
} catch (Exception e) {
  baz();
}

如果bar() 中的异常没有被捕获,并且foo() 中的异常阻止bar() 运行(bar() 总是被执行),那么构造相当于:

try {
  foo();
} catch (Exception e) {
  baz();
} finally {
  bar();
}

如您所见,这种 between-try-catch 构造的任何合理语义都已经可以表达,而无需新的——而且相当混乱的——构造。很难为这个不冗余的结构设计一个含义。

顺便说一句,我们不能这样做的一个潜在原因是:

try {
  foo();
} finally {
  bar();
} catch (Exception e) {
  baz();
}

可能是它不反映实际的执行顺序 - catch 块在 finally 块之前运行 。这允许 catch 块利用 finally 块可能稍后释放的资源(例如,从 RPC 对象或其他东西请求额外的诊断信息)。也可以以另一种方式工作吗?当然。这值得么?应该不会吧。

【讨论】:

    【解决方案3】:

    嗯,它的意思是这样的:

    try
    {
       somCode();
    }
    someMoreCode();
    catch
    {
    }
    

    这应该是什么意思? 这是不可能的,因为它没有语义,因此语言设计者认为它在语法上是不正确的!

    【讨论】:

    • 是的,它是……一个短的,一个比你的短的,这是真的,但确实如此。我说的完全正确:编译器无法分析,因为java设计者认为它没有意义,所以它被语法禁止。就像我说的“汽车火鸡吃”一样:它没有语义,因此被语法禁止
    【解决方案4】:

    如果您有try,则必须有catchfinallyas defined in the java language specification, 14.20 "The try Statement`

    【讨论】:

      【解决方案5】:

      试着抓住 .. if 和 else .. 所以不需要在try和catch块之间加代码

      【讨论】: