Try/finally без значения catch и return
У меня есть следующая программа:
public class Main {
public static void main(String[] args)throws Exception
{
int res = test();
System.out.println("after call , res = " + res) ;
}
public static int test()throws Exception
{
try
{
return 10/0;
}
finally
{
System.out.println("finally") ;
}
}
}
после запуска над программой, следующая команда результата в консоли:
finally
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.test(Main.java:17)
at Main.main(Main.java:7)
это поведение нормально, потому что исключение выбрано главным методом.
Затем я меняю код следующим образом:
public class Main {
public static void main(String[] args)throws Exception
{
int res = test();
System.out.println("after call , res = " + res) ;
}
public static int test()throws Exception
{
try
{
return 10/0;
}
finally
{
System.out.println("finally") ;
return 20;
}
}
}
При запуске программы я увидел следующий результат в консоли:
finally
after call , res = 20
Мой вопрос связан со вторым форматом. Почему при возврате в блок finally исключение не выбрасывается в основной метод?
Ответы
Ответ 1
Из JLS (внимание мое):
Если выполнение блока try завершается внезапно из-за броска значение V, то есть выбор:
[...]
Если тип времени выполнения V не является присвоением, совместимым с уловимым классом исключений любого предложения catch из инструкции try, тогда, наконец, блок выполняется. Тогда есть выбор:
-
Если блок finally завершается нормально, то оператор try внезапно завершается из-за выброса значения V.
-
Если блок finally завершается внезапно для разума S, то оператор try внезапно завершается по причине S (, а значение V отброшен и забыт).
TL/DR
Это означает, что если вы return
в блоке finally
, метод возвращается без исключения исключения.
/TL/DR
Помимо return
, существуют другие выражения, которые могут привести к тому, что блок finally
завершится внезапно и забудет об исключении. Они определены в JLS Section 14.1. По существу, это break
, continue
, return
или исключение (вызывается или вызвано оператором/методом). По этой причине завершается полный блок try/catch/finally
.
Есть еще несколько случаев в спецификации try/catch/finally
, особенно если нет исключения или существует соответствующее предложение catch. Это сводится к finally
бьет catch
бьет try
.
Ответ 2
Когда ваше исключение выбрано, , он сначала пройдет через ваш блок finally
.
Если ваш блок finally
не возвращает или не бросает ничего, тогда исходное исключение передается.
Если ваш блок finally
с другой стороны возвращает значение, , то исключение больше не распространяется.
Ответ 3
Посмотрите на выполнение try catch наконец.
Из спецификация java языка -jls-14.20.2
Если тип времени выполнения V не присваивается совместимым с уловимым классом исключений любого предложения catch из инструкции try, тогда выполняется блок finally. Тогда есть выбор:
Если блок finally завершается нормально, то инструкция try завершается внезапно из-за выброса значения V.
Если блок finally завершится внезапно для разума S, то оператор try внезапно завершится по причине S (, а выброс значения V будет отброшен и забыт).
Ответ 4
- Если вы используете
return
в разделе finally
, вы теряете исключение. Метод будет закончен с нормальным типом возвращаемого значения.
- Если вы не используете
return
в разделе finally
, в вашем случае метод будет завершен с исключением.
Первый случай:
try {
throw new Exception();
} finally {
//Exception will be lost, normal shutdown of the method
return;
}
Второй случай:
try {
throw new Exception();
} finally {
//Exception won't be lost, we'll get Exception in the main method
}
Третий случай:
try {
throw new Exception();
} finally {
throw new IOException();
// we lost Exception, IOException will be thrown
}
Примечание. Использование раздела finally
для исключения исключений или для возврата значений является плохой практикой. Этот раздел был создан, например, для закрытия внешних ресурсов.
Ответ 5
Все в блоке finally выполняется до того, как будет выбрано исключение, поэтому, если вы вернетесь в блок finally, исключение не будет выбрано вообще. По этой причине, как правило, плохая идея вернуться из блока finally.
Посмотрите этот блог для получения некоторой информации об этом.
Ответ 6
Java return
не всегда возвращается, this может развлекаться.
Ответ 7
Операция return в блоке finally была в основном остановлена исключение, которое произошло в блоке try от распространения вверх хотя он не был пойман.
Но компилятор Java уведомляет предупреждения при написании этого фрагмента кода.
Хотя return statements
всегда должен лежать в try block
, а блок finally
- uasully для releasing/closing connections, pointers etc.
Кажется, что ведет себя Java
.
Посмотрите здесь
Ответ 8
Если вы, наконец, прочтете java doc, тогда он говорит:
он позволяет программисту избежать случайного обхода кода очистки путем возврата, продолжения или разрыва. Помещение кода очистки в блок finally всегда является хорошей практикой, даже если не ожидается никаких исключений.
Итак, если вы поместите код очистки после блока finally, он не будет вызван, если есть исключение.
Ответ 9
В первом случае, наконец, блок выполняется как его поведение, но он не поймал исключение, но исключение выбрасывается с помощью основного метода. Проверьте это в этом примере
public class HelloWorld{
public static void main(String []args)throws Exception
{
try
{
int res = test();
System.out.println("after call , res = " + res) ;
}
catch(Exception ex)
{
System.out.println("Main Catch") ;
}
}
public static int test()throws Exception
{
try
{
return 10/0;
}
finally
{
System.out.println("finally") ;
}
}
}
В приведенном выше коде Main Catch
был выполнен.
Во втором случае вы вернули номер, поэтому в основном методе не было исключения.
Ответ 10
Поскольку окончательный блок всегда выполняется, возникает ли исключение или нет, а , если вы вернетесь из finally, вы отправляете свое исполнение вызывающему методу и вы теряете исключение. Поэтому он также генерирует предупреждение.
![введите описание изображения здесь]()
Ответ 11
В первой программе, когда ArithmeticException происходит в блоке try, затем вызывается блок finally и после выполнения блока finally возникает исключение. потому что исключение не обрабатывается программой. Вторая программа, когда, наконец, выполняется блок после выполнения этого оператора return и не возникает никакого исключения, потому что после того, как оператор return выполнит возврат компилятора в основном методе, а оставшееся выполнение не будет выполнено в последнем блоке. Поэтому исключение не произойдет.