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

Факторинг окончательного {...} блока

Интересно, являются ли следующие два swnippest семантически идентичными и, если нет, каковы различия (мы предполагаем, что мы хотим вычислить результат типа R и хотим защитить от исключения X, которое может быть выбрано в ход этого):

public R tcf(....) {
   try {
       R some = ...;
       ... compute the result ....
       return some; 
   }
   catch (X exception) {
       ... exception handling ....
   }
   finally {
       ... clean up ....
   }
}

и следующее:

public R tc(....) {
   try {
       R some = ...;
       ... compute the result ....
       return some; 
   }
   catch (X exception) {
       ... exception handling ....
   }
}

public R tf(....) {
    try {
        return tc(....);  // wrap the try-catch in tc()
    }
    finally {
        ... clean up ....
    }
 }

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

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

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

Скорее, я хочу убедиться, что пример 2 можно безопасно реорганизовать в пример 1.

4b9b3361

Ответ 1

Функционально они эквивалентны.

Я считаю, что хороший стиль выполняет очистку в том же методе, который выделил ресурсы, о которых идет речь. В некоторых случаях это единственный практический способ обойти вещи (например, если очистка включает переменные, которые являются локальными для tcf/tc).

Кроме того, если tc не очищается после себя, очистка становится частью контракта функции, как обязательство вызывающего абонента. Это делает дизайн более подверженным ошибкам, так как очистка легко забыть или ошибиться. Кроме того, если какие-либо действия, связанные с очисткой, изменяются, каждый вызывающий абонент должен быть отслежен и обновлен.

Нижняя строка: если очистка может быть выполнена в tcf, это должно быть.

Ответ 2

Тем не менее, они одинаковы. Попытка/наконец всегда должна быть права после того, как будет исправлено обращение (окончательно выпущенное). (обратите внимание, что это происходит непосредственно перед попыткой)

Например:

   getLock();
   try {
       doSomething()
   }
   finally {
       releaseLock();
   }

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

Ответ 3

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

Ответ 4

Я думаю, что ваше описание довольно точно в том, что tf finally будет выполняться в обоих случаях и что обработка исключений будет рассмотрена в блоке tcf или tf catch.

То есть в примере (1): если в вашем try возникает исключение, поток выполнит ваш блок catch, а затем ваш finally block. В примере (2), в tc, если в вашем блоке try возникает исключение, поток будет продолжаться в вашем блоке catch, а затем (предположим, что исключение не будет повторно выбрано), вернитесь к вызывающей строке в tf. По завершении блока tf try поток будет продолжаться в вашем блоке tf finally.

Я предполагаю, что главная причина, о которой нужно знать, и что вы не можете исправить в том, как вы предлагаете, заключается в следующем:

  • Если вы реализуете свой код, как в своем втором примере, вы не сможете получить доступ к ресурсам tc из tf, чтобы их очистить.
  • Даже если вы можете, вы очищаете ресурсы на уровне, который не близок к использованию ресурсов и может даже не использоваться другим клиентским кодом фреймворка. Я предполагаю, что вопрос документации и обучения.

Ответ 5

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

try может использоваться либо с catch, либо, наконец, или с обоими. наконец, вообще не может показать, что произошло исключение, но catch может отслеживать исключение.