2015-10-13 2 views
18

У меня есть программа следующим образом:попытка/наконец без улова и возвращаемого значения

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 исключение не выбрасывается в основной метод?

+2

@Tunaki Не то. –

+1

Возможно, это возможно: http://stackoverflow.com/q/48088/1743880? – Tunaki

+0

Пожалуйста, посмотрите: http://stackoverflow.com/questions/48088/returning-from-a-finally-block-in-java – Rehman

ответ

7

Из JLS (курсив мой):

Если выполнение блока Ьгу завершается преждевременно из-за броска значение V, то есть выбор:
[...]
Если тип времени выполнения V не является присвоением, совместимым с уловимым классом исключений любого предложения catch в заявлении try, тогда выполняется окончательный блок . Тогда есть выбор:

  • Если, наконец, блок завершается нормально, то оператор попытки завершается преждевременно из-за забросом значения V.

  • Если, наконец, блок завершается преждевременно по причине S, то инструкция try внезапно завершается по причине S (и выбросом значения V является отброшено и забыто).

TL/DR
Это означает, что если вы return в пределах finally блока, метод возвращает без бросать исключение.
/TL/DR

return Кроме того, существуют и другие statementes, которые могут привести к finally блок полной покруче и забыть об исключении. Они определены в JLS Section 14.1. В основном, это break, continue, return или исключение (вызванное или вызванное оператором/методом). По этой причине завершается полный блок try/catch/finally.

Есть еще несколько случаев в спецификации try/catch/finally, особенно если нет исключений или существует соответствующее предложение catch. Это сводится к finally бьет catch бьет try.

3
  1. Если вы используете return в разделе finally, вы теряете исключение. Метод будет закончен с нормальным типом возвращаемого значения.
  2. Если вы не используете 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 для исключения исключений или для возврата значений является плохой практикой. Этот раздел был создан, например, для закрытия внешних ресурсов.

0

Java return не всегда возвращается, this может развлечь.

13

Когда ваше исключение выбрано, он сначала пройдет через ваш блок finally.

Если ваш блок finally не возвращает или ничего не бросает, то исходное исключение передается.

Если ваш блок finally с другой стороны возвращает значение, , то исключение больше не распространяется.

2

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

Посмотрите на this blog для получения информации об этом.

8

Посмотрите на выполнение попытки поймать наконец.

java language specification -jls-14.20.2 От

Если типа вводного времени V не уступка совместит с catchable классом исключения из любого пункта уловов заявления попробовать, то, наконец, блок выполняется. Тогда есть выбор:

Если, наконец, блок завершается нормально, то оператор попытки завершается преждевременно из-за заброс значения V.

Если, наконец, блок завершается преждевременно по причине S, то попытка заявление завершается внезапно по причине S (и выброс значения V отбрасывается и забывается).

+1

Просто интересно, какая причина S? – bvdb

+1

@bvdb В этом случае исключение. –

+1

@bvdb JLS 14.1: https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html; Sloppy сказал: Это может быть любая инструкция, которая останавливает блокировку от конца в ее концевой скобке: «break», 'continue',' return' или исключение. – flo

0

Возвращение statementin окончательно блок был в основном остановив исключением того, что произошло в блоке Ьгу от распространяющихся вверх даже , хотя он не был пойман.

Но компилятор Java предупреждает о предупреждениях при написании этого фрагмента кода. Хотя return statements всегда должна лежать в try block и finally блок uasully для releasing/closing connections, pointers etc.

Похоже на пути Java ведет себя.

Взгляните here

0

Если вы читали Java документ окончательно, то он говорит,

позволяет программисту, чтобы избежать очищающий код случайно исключенных возвращением, по-прежнему, или сломаться. Включение кода очистки в блок finally всегда является хорошей практикой, даже если не ожидается никаких исключений.

Так что если вы поместите код очистки после блока finally, он не будет вызван, если есть исключение.

0

В первом случае, наконец, блок выполняется как его поведение, но оно не попало в исключение, но исключение выбрасывается с помощью основного метода. Проверьте это с помощью этого примера

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 был выполнен.

Во втором случае вы вернули номер, поэтому в основном методе не было исключения.

0

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

enter image description here

0

В первой программе, когда ArithmeticException происходят в Ьгу блоке затем вызвать, наконец, блок и после выполнения окончательно блокировать, произошло исключение. потому что исключение не обрабатывается программой. Вторая программа, когда, наконец, выполняется блок после выполнения этого оператора return и не возникает никакого исключения, потому что после того, как оператор return выполнит возврат компилятора в основном методе, а оставшееся выполнение не будет выполнено в окончательном блоке. Поэтому исключение не произойдет.