【问题标题】:Exception is swallowed by finally异常被finally吞噬
【发布时间】:2016-06-29 01:46:22
【问题描述】:
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() 必须throws Exception。但是什么也没发生,该方法返回 2。

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

编辑:感谢所有答案。你们中的一些人忽略了方法称为retIntExc 的事实,这意味着这只是一些测试/实验示例,显示了投掷/捕捉机制的问题。我不需要“修复”,我需要解释为什么会发生这种情况。

【问题讨论】:

标签: java exception


【解决方案1】:

这就是你不能从 C# 中的 finally 块返回的原因:)

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

如果 finally 块由于原因 S 突然完成,则 try 语句由于原因 S 突然完成(并且值 V 的抛出被丢弃并被遗忘)。

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

上面的引用来自这组嵌套的要点,省略了不适用的选项:

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

【讨论】:

  • 谢谢。这就是我需要的 - JLS 参考。
  • 尚未在 Java 17 LTS 中修复?
  • @Pacerier:我不确定你所说的“固定”是什么意思——它不是已经按照指定的方式运行了吗?
【解决方案2】:

它将返回2,因为

finally 总是执行

【讨论】:

  • -1 最终并不总是执行并且它不打印任何东西。
  • 请试试这个。 System.out.println(retIntExc());请在投票之前三思而后行!
  • finally 实际上并不总是执行。
【解决方案3】:

无论抛出什么异常,finally 块都会执行。它不仅仅在您声明的catch 块捕获异常之后执行。它在try 块之后执行如果有异常则捕获。如果你的方法抛出一个异常,它不能返回任何东西,除非你在你的方法中吞下它并返回result。但你不能两者兼得。

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

【讨论】:

    【解决方案4】:

    这是因为您在通过异常之前发出了 return 语句,因此返回了一个有效值。不能既返回值又抛出异常。

    删除 return 周围的 finally 块将给出您想要的行为。

    【讨论】:

      【解决方案5】:

      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;
              }
          }
      

      【讨论】:

        【解决方案6】:

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

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

        然后您抛出一个异常,但您的 catch 块捕获不同类型的异常,因此不执行任何操作。

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

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

        这个成功的返回推翻了冒泡异常。如果您希望异常继续冒泡,那么您不能在 finally 块中返回。

        【讨论】:

          【解决方案7】:

          通过将return 放在 finally 方法中,您将覆盖抛出的异常并返回结果。你的代码应该是这样的:

          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;
              }
          

          【讨论】:

            猜你喜欢
            • 2016-04-23
            • 1970-01-01
            • 2020-08-27
            • 2011-02-05
            • 1970-01-01
            • 1970-01-01
            • 2015-11-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多