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

Вопрос о возврате дизайна Java try-finally

В Java, try {...} finally {...} выполняется несколько неинтуитивно для меня. Как проиллюстрировано в другом вопросе, Выполняется ли окончательно в Java?, если у вас есть оператор return в блоке try, он будет проигнорирован, если определен окончательный блок. Например, функция

boolean test () {
    try {
        return true;
    }
    finally {
        return false;
    }
}

всегда возвращает false. Мой вопрос: почему это? Есть ли особая философия, лежащая в основе этого дизайнерского решения Java? Я ценю любую проницательность, спасибо.

Изменить: меня особенно интересует "почему" Java считает, что это нормально, чтобы нарушить семантику, которую я определяю. Если я вернусь в блок try, метод должен вернуться туда и обратно. Но JVM решает проигнорировать мою инструкцию и вернуться из подпрограммы, которая на самом деле еще не достигнута.

4b9b3361

Ответ 1

С технической точки зрения, return в блоке try не будет игнорироваться, если будет определен блок finally, только если этот блок finally также включает return.

Это сомнительное дизайнерское решение, которое, вероятно, было ошибкой в ​​ретроспективе (так же, как ссылки были обнуляемыми/изменяемыми по умолчанию и, по некоторым данным, проверенными исключениями). Во многом это поведение в точности согласуется с разговорной концепцией того, что означает finally - "независимо от того, что происходит заранее в блоке try, всегда запускайте этот код". Следовательно, если вы return true из блока finally, общий эффект должен всегда состоять в том, чтобы возвращать true, no?

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

Ответ 2

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

В других местах это также обсуждается в книге Java Puzzlers.

Ответ 3

Конструкция finally - это средство, предоставляемое JLS для обработки кода, подверженного некоторому исключению. разработчик может использовать это средство для обеспечения изящного восстановления из исключения. использовать конструкцию finally так, как вы описали, не подходит для хорошей практики. в этом отношении, никогда не бывает хорошо return что-либо из блока finally.
так как вы asekd, "философия" - это обработка любого внезапного завершения кода. если требуется вернуть определенное значение как часть обработки такого состояния, это должно быть сделано в блоке catch.

Ответ 4

Если вы вызываете javac с -Xlint, тогда будет создано соответствующее предупреждение, указывающее, что вы не должны вызывать возврат из предложения finally. Например (компиляция простого класса с помощью вышеописанного метода test()):

javac -Xlint foo.java
foo.java:13: warning: [finally] finally clause cannot complete normally
    }
^
1 warning

Ответ 5

проверьте это для справки   Выполняется ли окончательно на Java?

"Оператор try с блоком finally выполняется, сначала выполнив блок try. Тогда есть выбор:
Если выполнение блока try завершается нормально, [...]
Если выполнение блока try завершается внезапно из-за выброса значения V, [...]
Если выполнение блока try завершается внезапно по любой другой причине R, тогда выполняется блок finally. Тогда есть выбор:
Если блок finally завершается нормально, то оператор try внезапно завершается по причине R.
Если блок finally завершится внезапно для разума S, то оператор try внезапно завершится по причине S (и причина R отбрасывается).

Ответ 6

Хотя блок finally создан для закрытия ресурсов, и оператор return обычно не должен быть там, и Eclipse предупреждает, что "окончательный блок не выполняется нормально", я обнаружил, что в некоторых случаях "окончательный возврат" по-прежнему желательно.

ResponseType response = new ResponseType();
try{
    //set some properties of the response object.
    response.setStatus(1);
    //return response;
}catch (Exception e){
    //Some other properties of the response object according to the exception.
    response.setStatus(0);
    //return response;
}finally{
    return response;
}

Если я не поставлю предложение return в блоке finally, мне придется повторить его в try и catch block, а текущий код немного яснее.