Почему в этом коде требуется блок finally

Я знаю, что можно создать сегмент try-catch без блока finally. Итак, взламывая этот код, я не могу понять, какая логика Java (например, правило, теория) заставляет меня включать блок finally в этот сегмент кода - и почему блок finally должен включать в себя оператор возврата. Другими словами, если я полностью удаляю блок finally, я получаю сообщение об ошибке, и если я заменяю оператор return в блоке finally чем-либо еще (например, System.out.printl(''foo")), я все равно получаю сообщение об ошибке. настаивая на включении оператора return. Опять же, код, написанный здесь, компилируется и работает нормально. Я просто пытаюсь немного понять теорию, лежащую в основе конструкции try-catch-finally (p.s. я понимаю, что все дело в " обработка исключений"... но мой вопрос больше касается потока кода и оператора return).

class foo {
    int getInt() {
        try {
            String[] students = {"student1", "student2"};
            System.out.println(students[4]);
        }
        catch (Exception e) {
            return 10;
        }
        finally {
            return 20;
        }
    }
    public static void main(String args[]) {
        foo classSize = new foo();
        System.out.println(classSize.getInt());
    }
}

person Michael    schedule 06.07.2014    source источник
comment
Хитрость заключается в том, чтобы прочитать сообщение об ошибке. Без блока finally, если нет исключения, что возвращает метод?   -  person JB Nizet    schedule 07.07.2014
comment
С таким же успехом return 20 может находиться за пределами try/catch, в конце метода или в конце блока try. Однако нет ничего плохого в том, как это сделано выше.   -  person Hot Licks    schedule 07.07.2014
comment
Наличие блока finally исправляет компиляцию, но логически это ошибка.   -  person Sergey Kalinichenko    schedule 07.07.2014
comment
(Я бы предпочел, чтобы метод был в конце. Или поместите туда комментарий, указывающий, где предполагается return.)   -  person Hot Licks    schedule 07.07.2014
comment
Кто-то задает вам вопрос с подвохом. Заменяет ли 20 в блоке finally, который будет выполняться после блока catch, 10? [Подсказка: да] return в блоках finally разрешено, но плохая идея.   -  person Andrew Lazarus    schedule 07.07.2014
comment
Если я включу допустимое значение (например, 0) в качестве длины массива, но удалю блок finally, я получу ту же ошибку [отсутствует оператор возврата].   -  person Michael    schedule 07.07.2014
comment
@AndrewLazarus - Отлично!   -  person Hot Licks    schedule 07.07.2014
comment
@HotLicks: в большинстве случаев он должен находиться внутри блока try, потому что он должен возвращать что-то, что доступно только в пределах блока try.   -  person JB Nizet    schedule 07.07.2014
comment
Правило состоит в том, что для метода, возвращающего значение, должен быть оператор return <some_value>; вдоль КАЖДОГО пути к выходу из метода без исключения. Если вы удалите return в предложении finally и не замените его другим в другом месте, то метод может выйти без указания возвращаемого значения.   -  person Hot Licks    schedule 07.07.2014
comment
Андрей. Вы правы. Это вопрос с подвохом, и я понимаю, что return в блоке finally переопределит оператор return в блоке catch. Я также понимаю, что логически способ написания этого кода не слишком ярок. Я понимаю. Я просто пытаюсь понять, почему я ВЫНУЖДЕН включать блок finally с возвращаемым значением вообще...?   -  person Michael    schedule 07.07.2014
comment
Спасибо Hot Licks. Это делает меня намного ближе!   -  person Michael    schedule 07.07.2014
comment
@dasblinklight Спасибо. Тоже имеет смысл.   -  person Michael    schedule 07.07.2014


Ответы (1)


Рассмотрим пути выполнения без finally

int getInt() {
    try {
        String[] students = {"student1", "student2"};
        System.out.println(students[4]);
        // no return
    }
    catch (Exception e) {
        return 10; // if an exception occurs 
    }
    // no return
}

Итак, что произойдет, если исключение не будет выброшено? У вас не будет возвращаемого значения.

Вы можете либо предоставить finally и поместить возврат туда, либо вы можете поместить возврат вне блока try-catch.

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

int getInt() {
    try {
        String[] students = {"student1", "student2"};
        System.out.println(students[4]);
        // the return could be here as well
    }
    catch (Exception e) {
        return 10; // in case of failure
    }
    return 20; // in case of success
}

Все пути выполнения должны возвращать значение (или вызывать исключение).

person Sotirios Delimanolis    schedule 06.07.2014
comment
или поставить return в конце блока try (наиболее естественное место для меня) - person JB Nizet; 07.07.2014
comment
Таким образом, если возникает ошибка, то последний блок не выполняется, потому что блок catch уже возвращает значение. Это верно? - person bbalchev; 07.07.2014
comment
@bbalchev: нет. Блок finally всегда выполняется. В этом весь смысл блока finally. - person JB Nizet; 07.07.2014
comment
Хорошо, спасибо. Также всегда полезно учиться на каверзных вопросах. - person bbalchev; 07.07.2014
comment
Это было предложено другим комментатором. Написание такого кода не будет компилироваться. Я получаю ту же ошибку. [например. ошибка: отсутствует оператор возврата] - person Michael; 07.07.2014
comment
На самом деле Eclipse выдает предупреждение об избыточном finally. Он предлагает: @SuppressWarnings (наконец-то) - person bbalchev; 07.07.2014
comment
@vee Вы имеете в виду первый фрагмент кода? Обратите внимание на то, что он говорит: «Рассмотрите пути выполнения без finally. Он не предназначен для компиляции. Это демонстрирует, почему он терпит неудачу, если нет finally (или другого оператора return). - person Sotirios Delimanolis; 07.07.2014
comment
@SotiriosDelimanolis Имеет смысл. Мне придется немного поиграть с ним, чтобы владеть им. Но теперь я вижу логику. Спасибо - person Michael; 07.07.2014