Использование выражения finally

Это очень простой вопрос. В Java я использую выражение finally для закрытия ресурсов, потому что "это хорошая практика". Я развивался в Javascript, а затем в Node.js в течение нескольких лет, а никогда использовал оператор finally. Я знаю, что в Node.js мы все следим за первым шаблоном обработки ошибок. В любом случае, следующие два фрагмента сделают то же самое:

try{
    throw 123
}catch (e){

}finally{
    console.log(1)
}

.

try{
    throw 123
}catch (e){

}

console.log(1)

Оба печатают 1.

Почему finally ключевое слово, если оно не имеет реальной выгоды? Код очистки можно поместить внутри улова.

Ответ 1

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

Просто простой и понятный пример, который показывает разницу. Есть return который нарушает завершение функции, но console.log в finally вызывается, пока пропускается последний console.log.

let letsTry = () => {

  try {
    // there is a SyntaxError
    eval('alert("Hello world)');
    
  } catch(error) {
    console.error(error);
	
    // break the function completion
    return;
  } finally {
      console.log('finally')
  }

  // This line will never get executed
  console.log('after try catch')
}

letsTry();

Ответ 2

Но попробуйте это:

try {
    throw "foo"
} catch (e) {
    throw "bar"
} finally {
    console.log("baz")
}

console.log("quux")

Если из блока catch выдается вторая ошибка, код после блока try...catch не будет запущен.
Блок finally всегда запускается, даже если в блоке catch обнаружена ошибка.

Кроме того, блок finally выполняется, даже если оператор return или break останавливает код в блоке try или catch. операторы return в блоке finally переопределяют операторы return в блоке try или catch.

function foo() {
    try {
        return "bar";
    } finally {
        return "baz";
    }
}

foo() // "baz"

Ответ 3

oracle docs дают хороший ответ на это. Итог: наконец, называется всегда! Даже если вы поймаете только один вид исключения (а не глобальный catch), тогда, наконец, вызывается (после чего ваше приложение, вероятно, ломается, если нет другого улова)

Ответ 4

блок finally предназначен для специального назначения.

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

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

Ответ 5

Что если блок try возвращается рано или выдает исключение, которое вы не обрабатываете? Вы все еще хотите освободить ресурсы, которые вы выделили, верно?


РЕДАКТИРОВАТЬ:

Ответы на этот вопрос кажутся почти философскими, есть некоторые "догадки", и в основном "мы считаем, что это должно быть полезно, потому что оно есть, поэтому его нужно использовать", и "даже Oracle так говорит". Или, может быть, это поможет программисту не "забыть что-то" или "случайно выйти и не осознать это".

Это почти все веские причины, но есть и техническая причина.

Это помогает избежать дублирования кода в упомянутых случаях, когда (a) возвращается либо try, либо один из блоков catch, либо (b) если в блоке catch выдается второе исключение.

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

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

Так что, если вы уверены, что не пропустите его как случай (a) или (b), вы все равно можете поместить код 'finally' после блока try/catch и опустить предложение finally.

Но что, если ситуация изменится? Когда вы или другой человек измените код на более позднем этапе, можно забыть проверить, не пропущен ли сейчас код очистки в какой-либо ситуации.

Так почему бы не всегда помещать код очистки в блок finally? И это то, что рекомендуется и то, что делают многие программисты JavaScript.

Ответ 6

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

InputStream is = new FileInputStream("C://test.txt");
try {
    //code...
} catch (Exception e) {
    //code...
} finally {
    is.close();
}

Ответ 7

Это очень хороший вопрос.

В javascript нет смысла использовать finally, но я могу представить себе ситуации, в которых это может быть полезно.

Предположим, у вас есть веб-страница, где вы показываете определенный div после некоторого действия пользователя, например. кнопка нажата.
div показывает некоторые записи, например, для действия, которое пользователь запросил.
По завершении действия (ошибка или отсутствие ошибки) вы хотите снова скрыть div. Для этого вы можете использовать предложение finally.

function doSomething() {
    var d = document.getElementById("log");
    show(d);
    try {
        ... execute action ...
    } catch(e) {
        log(e);
    } finally {
        hide(d);
    }
}

В целом, как вы уже упоминали, исключения используются в JavaScript в пользу обратных вызовов ошибок. Таким образом, можно было бы также спросить, какие пользы для исключений в JavaScript вообще.

Ответ 8

В Java, если возникло исключение, не совпадающее с какими-либо из выполнения блокировок, будет разорвано, и все открытые ресурсы будут оставлены открытыми. Блок finally всегда будет выполнен, даже если возникает неперехваченное исключение.

Ответ 9

Возможно, для этого случая

try{
    throw 123
} finally {
    console.log(1)
}