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

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

4b9b3361

Ответ 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 выполнит возврат компилятора в основном методе, а оставшееся выполнение не будет выполнено в последнем блоке. Поэтому исключение не произойдет.