2012-07-11 66 views
6

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

能否请你帮我...

+8

您对第一个问题的回答是错误的。编译器不会认为没有“catch”块。它显然仍然存在于你的代码中,并且它在“finally”块后面出现的事实将导致编译时错误。 – BoltClock 2012-07-11 06:40:04

+0

BoltClock是正确的 - 你的第一个问题会出现编译错误。 * catch *必须立即放在* try * – StuartLC 2012-07-11 06:44:40

+1

之后catch语句必须在try块之后立即执行。没有其他原因。 – Sabbath 2012-07-11 06:47:54

回答

4

那么这将意味着是这样的:

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

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

+1

是的,它是......短的,短的是你的,但它是真的。我所说的是完全正确的:编译器无法分析这个原因,因为java设计者认为它没有意义,所以它的语法是被禁止的。就好像我说的“汽车火鸡吃饭”一样:它没有语义,因此它迄今为止已被语法 – Kek 2012-07-11 07:05:57

0

尝试,赶上像..如果和别人.. 所以没有必要尝试和catch块之间添加代码

11

好吧,首先第一件事 - 编译器不会执行代码,它只是编译它,让它由JVM运行。

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

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

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

当异常被抛出,打印出该行Sup!仍将获得跳过的JVM正在搜索跳转到相应的异常处理程序来处理Exception。所以,从某种意义上来说,代码的行为与它在try {}模块本身中的行为是一样的,这就是为什么代码在哪里并不重要,而且Java规定这个(现在被证明是无用的)构造是非法的。

现在如果尝试之后的代码本身会抛出另一个异常呢?如果它是有效的代码,它的行为就像原始try块中的嵌套try ... catch块。当然,一旦事情变得复杂起来,尝试和catch块之间没有明确连接的方法可能会变得模糊,JVM最终不知道哪个catch/finally属于哪个try块(特别是因为处理程序不必处于相同的功能中,或者甚至不在同一个软件包中!)。

+0

禁止最佳答案! (+1) – alfasin 2012-07-11 07:00:44

+0

谢谢!添加了一些小东西(特别是关于我的小Java代码片段的错误的更清晰的声明) – 2012-07-11 07:02:49

+1

请注意,在JVM级别,不需要嵌套try块。你可以有'foo();酒吧(); baz();',并且同时具有'foo()'和'baz()'捕获异常并跳转到_same_ catch代码,而bar()转到另一个代码。发生的一切就是有一张表,显示哪些字节码范围转到哪些catch处理程序;编译器可以按照喜欢的方式设置该表。所以虽然这种构造可能会混淆javac,但JVM很乐意实现你为它定义的任何语义。 – bdonlan 2012-07-11 08:18:45

4

那么,轻浮的答案是,语言规范禁止它。

但让我们退后一步,以不同的方式思考 - 如果你可以做到这一点?

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对象的附加诊断信息等)。也可以用另一种方式工作?当然。这值得么?可能不会。