最终吞噬了例外

static int retIntExc() throws Exception{ int result = 1; try { result = 2; throw new IOException("Exception rised."); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.getMessage()); result = 3; } finally { return result; } } 

我的一个朋友是.NET开发人员,目前正在迁移到Java,他问我关于这个来源的以下问题。 理论上,这必须throw IOException("Exception rised.") retIntExc() throw IOException("Exception rised.")并且整个方法retIntExc()必须throws Exception 。 但没有任何反应,该方法返回2。

我没有测试他的例子,但我认为这不是预期的行为。

编辑:谢谢你的所有答案。 有些人忽略了这个方法被称为retIntExc的事实,这意味着这只是一些测试/实验示例,显示了抛出/捕捉机制中的问题。 我不需要’修复’,我需要解释为什么会这样。

这就是为什么你不能从C#中的finally块返回:)

这绝对是Java语言规范中规定的行为。 它在14.20.2节中规定 。

如果finally块因为原因S而突然完成,那么try语句突然完成原因S(并且丢弃并抛弃值V的抛出)。

返回是突然完成的一个例子; 如果finally块抛出exception,那么也会突然完成,丢失原始exception。

上面的引用来自这套嵌套的项目符号,省略了这里不适用的选项:

  • 如果try块的执行由于抛出值V而突然完成,那么有一个选择:
    • 如果V的运行时类型不能分配给try语句的任何catch子句的参数,则执行finally块。 然后有一个选择:
      • 如果finally块因为原因S而突然完成,那么try语句突然完成原因S(并且丢弃并抛弃值V的抛出)。

它将返回2因为

finally总是执行

无论抛出什么exception, finally块都会执行。 它不会在您声明的catch块捕获exception后执行。 它在try块之后执行, 如果有则捕获exception 。 如果您的方法抛出exception,除非您在方法中吞下它并返回result否则它不会返回任何内容。 但你不能兼得。

此外,除非您的方法有任何其他代码,否则也不会遇到ArrayIndexOutOfBoundsException

这是因为您在exception传递之前发出了一个return语句,因此返回了一个有效值。 您不能同时返回值并抛出exception。

删除返回周围的finally块将提供您想要的行为。

IOException类不是ArrayIndexOutOfBoundsException类的子类,因此将永远不会执行catch部分。

如果你改变它,它将返回3。

 static int retIntExc() throws Exception{ int result = 1; try { result = 2; throw new ArrayIndexOutOfBoundsException ("Exception rised."); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.getMessage()); result = 3; } finally { return result; } } 

我不明白为什么这不是预期的行为。 到此代码块结束时,结果等于2。

 static int retIntExc() throws Exception{ int result = 1; try { result = 2; 

然后抛出exception,但是catch块会捕获不同类型的exception,因此不会执行任何操作。

  throw new IOException("Exception rised."); } catch (ArrayIndexOutOfBoundsException e) { ... } 

保证finally块被执行,所以最后一步是返回2。

这次成功的回报否决了冒泡exception。 如果您希望exception继续冒泡,那么您不能返回finally块。

通过在finally方法中放置return来覆盖抛出的exception并返回结果。 你的代码应该是这样的:

 static int retIntExc() throws Exception{ int result = 1; try { result = 2; throw new IOException("Exception rised."); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(e.getMessage()); result = 3; } finally { // do something } // it gets here only when exception is not thrown return result; }