Возвращаясь из блока finally в Java

java exception return try-catch-finally

60785 просмотра

5 ответа

Недавно я был удивлен, обнаружив, что в блоке finally в Java возможно иметь оператор return.

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

Итак, мой вопрос, может ли кто-нибудь привести мне пример, когда оператор return (или другой элемент управления потоком) в блоке finally создает лучший / более читаемый код?

Автор: Matt Sheppard Источник Размещён: 29.07.2019 01:46

Ответы (5)


85 плюса

Решение

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

Даже если есть надуманный пример, где это «лучше», подумайте о разработчике, который должен поддерживать ваш код позже и который может не знать о тонкостях. Этот бедный разработчик может быть даже вы ....

Автор: Jason Cohen Размещён: 07.09.2008 03:20

136 плюса

У меня было ДЕЙСТВИТЕЛЬНО трудное время, чтобы отследить ошибку, которая была вызвана этим. Код был что-то вроде:

Object problemMethod() {
    Object rtn = null;
    try {
        rtn = somethingThatThrewAnException();
    }
    finally {
        doSomeCleanup();
        return rtn;
    }
}

Случилось так, что исключение было сгенерировано в другом коде. Он был пойман и зарегистрирован и переброшен в рамках somethingThatThrewAnException()метода. Но исключение не распространялось в прошлом problemMethod(). После долгого времени просмотра мы наконец отследили его до метода return. Метод return в блоке finally в основном останавливал распространение исключения, которое произошло в блоке try, даже если оно не было перехвачено.

Как уже говорили другие, хотя и законно возвращаться из блока finally в соответствии со спецификацией Java, это ПЛОХАЯ вещь, и ее не следует делать.

Автор: John Meagher Размещён: 07.09.2008 08:17

20 плюса

Javac будет предупреждать о возвращении в конце, если вы используете -Xlint: наконец. Первоначально javac не выдавал предупреждений - если что-то не так с кодом, он не должен компилироваться. К сожалению, обратная совместимость означает, что непредвиденная глупость не может быть запрещена.

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

Автор: Tom Hawtin - tackline Размещён: 07.09.2008 01:50

13 плюса

Добавление управляющих структур и возвращений в блоки finally {} - это еще один пример злоупотреблений «просто потому, что вы можете», которые распространены практически на всех языках разработки. Джейсон был прав, предполагая, что он легко может стать кошмаром обслуживания - аргументы против раннего возврата из функций в большей степени применимы к этому случаю «позднего возврата».

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

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

Автор: Ian Размещён: 07.09.2008 03:31

6 плюса

Простой Groovy тест:

public class Instance {

  List<String> runningThreads = new ArrayList<String>()

  void test(boolean returnInFinally) {

    println "\ntest(returnInFinally: $returnInFinally)"
    println "--------------------------------------------------------------------------"
    println "before execute"
    String result = execute(returnInFinally, false)
    println "after execute -> result: " + result
    println "--------------------------------------------------------------------------"

    println "before execute"
    try {
      result = execute(returnInFinally, true)
      println "after execute -> result: " + result
    } catch (Exception ex) {
      println "execute threw exception: " + ex.getMessage()
    }  
    println "--------------------------------------------------------------------------\n"

  }

  String execute(boolean returnInFinally, boolean throwError) {
      String thread = Thread.currentThread().getName()
      println "...execute(returnInFinally: $returnInFinally, throwError: $throwError) - thread: $thread"
      runningThreads.add(thread)
      try {
        if (throwError) {
          println "...error in execute, throw exception"
          throw new Exception("as you liked :-)")
        }
        println "...return 'OK' from execute"
        return "OK"
      } finally {
        println "...pass finally block"
        if (returnInFinally) return "return value from FINALLY ^^"
        // runningThreads.remove(thread)
      }
  }
}

Instance instance = new Instance()
instance.test(false)
instance.test(true)

Выход:

test(returnInFinally: false)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: OK
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
execute threw exception: as you liked :-)
-----------------------------------------------------------------------------


test(returnInFinally: true)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------

Вопрос:

Одним интересным моментом для меня было посмотреть, как Groovy справляется с неявными доходами. В Groovy можно «вернуться» из метода, просто оставив значение в конце (без возврата). Как вы думаете, что произойдет, если вы раскомментируете строку runningThreads.remove (..) в операторе finally - это перезапишет обычное возвращаемое значение («ОК») и охватит исключение ?!

Автор: Prof. Ondino Размещён: 04.03.2011 04:44
Вопросы из категории :
32x32