Вопрос

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

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

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

Это было полезно?

Решение

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

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

Другие советы

Много лет назад мне было ОЧЕНЬ трудно отследить ошибку, вызванную этим.Код был примерно таким:

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

Произошло следующее: исключение было выброшено в каком-то другом коде.Его ловили, регистрировали и снова бросали в somethingThatThrewAnException() метод.Но исключение не распространялось в прошлом problemMethod().После ДОЛГОГО времени рассмотрения этого вопроса мы наконец отследили его до метода возврата.Метод возврата в блоке Final по сути останавливал распространение исключения, возникшего в блоке try, даже если оно не было перехвачено.

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

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

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

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

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

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

Простой 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(..) строка в операторе Final – перезапишет ли это обычное возвращаемое значение («ОК») и покроет ли исключение?!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top