исключение потери в блокировке

Я запускаю этот код:

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

    }
}

Результат:
попытка: 1
улов: 2
наконец: 3
Исключение в потоке "main" java.lang.NullPointerException в user.main (User.java:17)

в улове блока - ArrayIndexOutOfBoundsException, но мы теряем это Exception, почему?


person user471011    schedule 17.10.2010    source источник


Ответы (3)


Из JLS

Вы можете прочитать об этом в JLS, блоках и утверждениях, раздел «14.19.2 Выполнение try-catch-finally». И я цитирую,

If execution of the try block completes abruptly for any other reason R, then the finally block is executed. Then there is a choice:
  • Если блок 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");
    }    
  }
}

Боковая панель о try с ресурсами / блоками ARM

Трудности с объяснением этого в некоторых распространенных случаях, особенно с управлением ресурсами, и необходимость вложенных блоков _4 _ / _ 5 _ / _ 6_ и вложенных внутри блоков finally, являются одной из причин использования функции «попытаться с ресурсом» в проекте COIN (которая должна быть интегрирована в Java "довольно скоро"), о которой вы можете прочитать здесь.

Это одна из многих веских причин потратить время на запуск статического анализатора, такого как PMD, который находит и жалуется на эту путаницу - хотя это может не уловить случай в вашем коде, Я не уверен.

Статическая проверка

Следите за комментарием от @stacktrace: я прогнал соответствующий код через PMD и FindBugs, попробовав оба из следующих :

finally { throw NullPointerException("Foo"); }

и

finally { Object o = null; System.out.println(o.toString()); }

Что касается первого, PMD заметила и пожаловалась на исключение, выброшенное из предложения finally. FindBugs вообще не жалуется. Что касается последнего, PMD жаловался на несколько вещей, но ничего не связанных («LocalVariableCouldBeFinal», «StringToString» и «UselessOperationOnImmutable»). Однако FindBugs заметил и пожаловался на разыменование null. Мораль истории? Запустите PMD и FindBugs!

Связанный

Связано с SO: Исключение глотания, выбранное в catch / finally. Могу ли я избежать такой громоздкой попытки / поймать / наконец ...

person andersoj    schedule 17.10.2010
comment
Такие инструменты, как findbug, предупредят вас об этом случае. - person Jayan; 18.10.2010

Вы только что наткнулись на странную особенность Java: если блок finally не завершается должным образом, он скрывает все исключения, которые были созданы ранее.

Это сделано намеренно, это не ошибка.

person Yoni    schedule 17.10.2010
comment
Смотрите мой ответ ... не много подробностей, но описано конкретно в JLS. - person andersoj; 17.10.2010

Последнее исключение не возникает внутри блока try { } catch { }, поэтому обработка catch { } или finally { } отсутствует.

person DigitalRoss    schedule 17.10.2010