块捕获中的丢失异常

use*_*011 6 java exception finally try-catch

我运行这段代码:

public class User {

    public static void main(String args[]) {
        int array[] = new int[10];
        int i = 1;
        try {
            System.out.println("try: " + i++);
            System.out.println(array[10]);
            System.out.println("try");
        } catch (Exception e) {
            System.out.println("catch: " + i++);
            System.out.println(array[10]);
            System.out.println("catch");
        } finally {
            System.out.println("finally: " + i++);
            Object o = null;
            o.hashCode();
            System.out.println("finally");
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

结果:
try:1
catch:2
finally:3
在user.main的线程"main"java.lang.NullPointerException中的异常(User.java:17)

在块catch中 - ArrayIndexOutOfBoundsException,但是我们丢失了这个Exception,为什么呢?

and*_*soj 7

来自JLS

您可以在JLS,块和语句的 "14.19.2 try-catch-finally的执行"部分中阅读此内容.我引述,

如果try块的执行由于任何其他原因R突然完成,则执行finally块.然后有一个选择:
  • 如果finally块正常完成,则try语句突然完成,原因是R.
  • 如果finally块由于原因S而突然完成,则try语句突然完成,原因S(并且原因R被丢弃).这个例子...

因此,以下(从提问者的代码中真正浓缩)完成了NPE,而不是ExceptionTest抛出.

class Phinally
{
  static class ExceptionTest extends Exception
  { public ExceptionTest(String message) { super(message); }  }

  public static void main(String[] args) throws ExceptionTest
  {
    try {
      System.out.println("Foo.");
      throw new ExceptionTest("throw from try"); 
    } finally {
      throw new NullPointerException("throw from finally");
    }    
  }
}
Run Code Online (Sandbox Code Playgroud)

关于try资源/ ARM块的侧边栏

在一些常见情况下,特别是在管理资源,需要嵌套try/ catch/ finally块和嵌套内部finally块的情况下,对此进行推理的难点是项目COIN中"尝试使用资源"功能的原因之一(即将很快集成到Java中) "),您可以在这里阅读更多相关信息.

这是投入时间运行像PMD这样的静态分析器的众多好理由之一,它发现并抱怨这种类型的混淆 - 虽然它可能无法捕捉到你的代码中的情况,但我不确定.

静态检查

跟进@stacktrace的评论:我通过PMD和FindBugs运行相关代码,尝试以下两种方法:

finally { throw NullPointerException("Foo"); }
Run Code Online (Sandbox Code Playgroud)

finally { Object o = null; System.out.println(o.toString()); }
Run Code Online (Sandbox Code Playgroud)

对于前者,PMD注意到并抱怨从一个finally条款中抛出异常.FindBugs根本没有抱怨.对于后者,PMD抱怨了几件但没有任何关系("LocalVariableCouldBeFinal","StringToString"和"UselessOperationOnImmutable").然而,FindBugs注意到并且抱怨了一个空取消引用.故事的道德启示?运行PMD和FindBugs!

有关

与SO相关:在catch/finally中抛出吞咽异常. 我可以避免这种繁琐的尝试/捕获/最终......