Подтвердить что ты не робот

Порядок улавливания исключений в Java

Если я не ошибаюсь, сначала следует поймать подклассы Исключения. Но нужно ли перехватывать любое RuntimeException и конкретное проверочное Exception, которое следует сначала поймать?

try {
    ...
} catch(RuntimeException e) {
    ...
} catch(IOException e) {
    ...
}

Правильно ли этот порядок? Или это правильно, но плохой вариант?

4b9b3361

Ответ 1

Порядок независимо от того, что соответствует первому, выполняется (как ясно объясняет JLS).

Если первый catch соответствует исключению, он выполняется, если нет, следующий будет проверяться и включаться и продолжаться до тех пор, пока не будет выбран один или нет.

Итак, когда вы ловите исключения, вы всегда хотите сначала поймать наиболее специфический, а затем самый общий (как RuntimeException или Exception). Например, представьте, что вы хотели бы поймать StringIndexOutOfBoundsException, брошенный String.charAt(index), но ваш код также мог бы выбросить NullPointerException, вот как вы можете поймать исключения:

String s = null;
try {
  s.charAt(10);
} catch ( NullPointerExeption e ) {
  System.out.println("null");
  e.printStackTrace();
} catch ( StringIndexOutOfBoundsException e ) {
  System.out.println("String index error!");
  e.printStackTrace();
} catch ( RuntimeException e ) {
  System.out.println("runtime exception!");
  e.printStackTrace();
}

Итак, с этим порядком, я убеждаюсь, что исключения пойманы правильно, и они не спотыкаются друг с другом, если это NullPointerException, он входит в первый catch, если StringIndexOutOfBoundsException он входит во второй и, наконец, если это что-то еще, что является RuntimeException (или наследуется от него, как IllegalArgumentException), он вводит третий улов.

Ваш случай верен, поскольку наследование IOException от Exception и RuntimeException также наследуется от Exception, поэтому они не будут перемещаться друг над другом.

Это также ошибка компиляции, чтобы сначала поймать общее исключение, а затем один из его потомков, как в:

try {
  // some code here
} catch ( Exception e) {
  e.printStackTrace();
} catch ( RuntimeException e ) { // this line will cause a compilation error because it would never be executed since the first catch would pick the exception
  e.printStackTrace();
}

Итак, сначала вы должны иметь детей, а затем родительские исключения.

Ответ 2

Правильно ли этот порядок? Или это правильно, но плохой вариант?

Ни. Как говорили другие ответы, компилятор должен сказать вам, если вы ставите простые уловы в порядке, где один маскирует другой.

Но в вашем коде есть еще одна потенциальная проблема: на самом деле вы вообще ловите RuntimeException. Проблема заключается в том, что существует множество источников/причин исключений uunchecked, и многие из этих источников/причин на самом деле являются ошибками в вашем приложении.

Использование catch для регистрации диагностики как части аварийного останова в порядке, но если вы поймаете и попытаетесь восстановиться после RuntimeException, вам нужно быть осторожным, чтобы вы не поддались серьезной проблеме под ковром:

  • Убедитесь, что вы регистрируете исключение и его стек, независимо от того, что.

  • Подумайте, целесообразно ли пытаться восстановить. Если у вас есть неизвестная ошибка, это может привести к непредсказуемому урону, прежде чем запускать исключение. Вы не можете узнать, может ли приложение восстановить или может ли он нанести худший ущерб, пытаясь продолжить.

Те же рекомендации относятся к ловле Exception и Throwable/Error. И это более важно с Throwable/Error из-за характера ущерба, который мог бы уже произойти.

Ответ 3

Любой порядок, который принимает компилятор, правильный.