try / finally без значения catch и return [duplicate]

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

задан Sam 13.10.2015 в 11:23
источник
  • @ Тунаки Не то. –  ꜱᴜʀᴇꜱʜ ᴀᴛᴛᴀ 13.10.2015 в 11:25
  • Возможно, это возможно: stackoverflow.com/q/48088/1743880? –  Tunaki 13.10.2015 в 11:27
  • Пожалуйста, посмотрите: stackoverflow.com/questions/48088/... –  Rehman 13.10.2015 в 11:27
  • Хорошо известно, что не использовать возврат в блоке finally, он не предназначен для такой вещи. Если вы это сделаете, исключение будет отброшено. –  Jean-Baptiste Yunès 13.10.2015 в 11:32

11 ответов

7

Из JLS (выделение мой):

  

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

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

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

  •   

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

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

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

    
ответ дан flo 13.10.2015 в 11:35
13

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

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

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

ответ дан bvdb 13.10.2015 в 11:29
8

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

Из спецификации языка Java -jls-14.20. 2

  

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

     

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

     

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

    
ответ дан ꜱᴜʀᴇꜱʜ ᴀᴛᴛᴀ 13.10.2015 в 11:31
  • Просто интересно, что такое причина S? –  bvdb 13.10.2015 в 11:37
  • @bvdb В этом случае исключение. –  ꜱᴜʀᴇꜱʜ ᴀᴛᴛᴀ 13.10.2015 в 11:42
  • @bvdb JLS 14.1: docs.oracle.com/javase/specs/jls/se8/html/jls-14.html; Sloppy сказал: Это может быть любая инструкция, которая останавливает блокирование от конца в ее концевой скобке: разрыв, продолжение, возврат или исключение. –  flo 13.10.2015 в 11:45
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 для генерации исключений или для возврата значений является плохой практикой. Этот раздел был создан, например, для закрытия внешних ресурсов.     

ответ дан Andrew 13.10.2015 в 11:28
2

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

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

ответ дан Ben Green 13.10.2015 в 11:30
0

Java return не всегда возвращается, это может понравиться.

    
ответ дан SK9 13.10.2015 в 11:28
0
  

Операция return в блоке finally была в основном остановлена   исключение, которое произошло в блоке try от распространения вверх   хотя он не был пойман.

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

Кажется, что поведение Java ведет себя.

Посмотрите здесь

    
ответ дан Ankur Singhal 13.10.2015 в 11:32
0

Если вы, наконец, прочтете java doc, тогда он говорит:

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

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

    
ответ дан Vishal Rathod 13.10.2015 в 11:33
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 получил выполнение.

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

    
ответ дан Harshit Shrivastava 13.10.2015 в 11:33
0

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

    

ответ дан Sindhoo Oad 13.10.2015 в 11:39
0
  

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

    
ответ дан Rakesh Raka 13.10.2015 в 12:04