Существует множество примеров того, как обработка исключений в Java может быть более сложной, чем может показаться на первый взгляд, и Джош Блох посвятил целую главу « Эффективная Java» (обе редакции) обработке исключений. Проверил модель исключения в Java остается « спорным .» Мне было приятно видеть, что бета-версия NetBeans 7.4, которую я недавно скачал, имеет некоторые советы, которые помогут хотя бы в нескольких нюансах обработки исключений Java.
Я недавно скачал бета- версию NetBeans 7.4 и установил эту последнюю версию NetBeans на свой ноутбук. Я загрузил пакет «Все» для загрузки IDE NetBeans (включая GlassFish Server Open Source Edition 4.0 и Apache Tomcat 7.0.41 и поддержку Groovy ) и установил его на свой компьютер.
Двумя новыми подсказками в категории «вероятных ошибок», которые есть в «текущей версии разработки» NetBeans, являются блок «finally» подавляет исключения »и« throw »внутри блока« finally ». В этом посте я продемонстрирую эти подсказки и кратко расскажу, почему эти подсказки помогают улучшить обработку исключений.
блок finally блокирует исключения
Как задокументировано в таких статьях, как James Stauffer « Не возвращаться» в предложении finally, а также в форумах, таких как Java, вопрос о дизайне try-finally return , общепринято, что возврат метода из блока finally — плохая идея. Пример этой плохой практики кодирования Java показан ниже.
Пример исключения блока наконец-то блокирующего
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
private void throwException() throws Exception{ throw new Exception("A checked exception!");}/** * Demonstrate NetBeans hint "The 'return' statement in the 'finally' block * discards unhandled exceptions" by returning a value from the "finally" * block. * * @return Integer value that is really meaningless in this case. * @throws RuntimeException This exception is always thrown. */public int demonstrateReturnFromFinallyBlock(){ int value = 5; try { value = 7; throwException(); } catch (Exception exception) { throw new RuntimeException(exception); } finally { return value; }} |
Когда метод demonstrateReturnFromFinallyBlock() в приведенном выше фрагменте кода выполняется, вывод выглядит следующим образом:
Возвращаемое значение: 7
Хотя можно было бы ожидать, что метод demonstrateReturnFromFinallyBlock() сгенерирует исключение Runtime вместо того, чтобы возвращать целочисленное значение 7 (поскольку Javadoc для этого метода даже объявляет!), Исключение «всегда выброшенное» фактически отбрасывается из-за оператора return в finally заблокировать. Это потенциально неприятная проблема, которая может быть очевидна только во время выполнения, а не во время компиляции. К счастью, бета-версия NetBeans 7.4 содержит подсказку об этой потенциальной проблеме, как показано на следующем снимке экрана:
На приведенном выше снимке экрана показано, что бета-версия NetBeans 7.4 предупреждает о состоянии оператора return в блоке finally , подчеркивая его желтым цветом. Это также показывает, что при наведении курсора на этот фрагмент кода, подчеркнутый желтым цветом, редактор NetBeans намекает: «Оператор return в блоке finally отменяет необработанные исключения».
Можно также узнать об этом же условии, передав -Xlint: finally компилятору javac . Очевидно, что это можно сделать в командной строке, о чем я ранее писал в параметрах -Xlint javac , но на следующем снимке экрана показано то же самое, что делается в NetBeans с помощью спецификации -Xlint:finally помощью параметра project.properties javac.compilerargs=-Xlint:finally .
блок ‘throw’ inside ‘finally’
Создание исключения изнутри блока finally как правило, является плохой идеей, поскольку оно будет скрывать все исключения, возникающие в блоке try связанном с блоком finally . Следующий листинг кода показывает пример этой плохой формы.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
/** * Demonstrate NetBeans hint warning that throwing an exception from a * 'finally' block is a bad idea because it hides the original exception. */public void demonstrateThrowFromFinallyBlock(){ Integer twoDividedByZero = null; try { twoDividedByZero = 2 / 0; } finally { if (twoDividedByZero == null) { throw new RuntimeException("Cannot calculate quotient with division."); } }} |
Кто-то может подумать, что выполнение вышеуказанного метода приведет к возникновению исключения ArithmeticException и может быть немного удивлено, когда вместо этого будет создано более общее (и родительское) RuntimeException .
На следующем снимке экрана показано предупреждение бета-версии NetBeans 7.4 об этом состоянии.
При наведении курсора на подчеркнутый желтым цветом код отображается предупреждение NetBeans «Оператор throw в блоке finally может скрыть исходное исключение». Снимок экрана выше показывает, что это именно то, что произошло в этом случае: ArithmeticException и его трассировка стека были скрыты RuntimeException выброшенным из блока finally .
Если я закомментирую строку, выдавшую исключение из блока finally , исходное исключение снова станет доступным. Это продемонстрировано на следующем снимке экрана.
Включение даже -Xlint:all (или просто -Xlint ) не будут предупреждать о плохой форме выброса исключения из блока finally . В этом конкретном примере -Xlint:devzero (или -Xlint:all или -Xlint ) показали бы, что в коде происходит деление на ноль, но в общем случае -Xlint не предупреждает вас, чтобы javac предупреждала вас при броске из Блок finally скрывает оригинальное исключение. Это делает этот конкретный намек NetBeans особенно полезным.
Вывод
Есть много нюансов и угловых случаев в обработке исключений Java. В бета-версии NetBeans 7.4 представлены две новые подсказки «вероятных ошибок», которые предупреждают об опасных действиях в блоках окончаний, связанных с исключениями. Эти два случая особенно коварны, потому что они обычно не перехватываются компилятором (хотя один из них может быть необязательно перехвачен в качестве предупреждения), не будут обнаружены до времени выполнения и вряд ли будут легко обнаружены при чтении и просмотре кода.


