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

Сколько кода вставляется в блок try-catch

Есть ли "лучший способ" для того, сколько кода помещается внутри блока try/catch?

Я разместил 3 разных сценария ниже.

Я не включил поведение в каждый блок catch, и я не включил блок finally. Это должно было улучшить читаемость для зрителей. Предположим, что каждый catch делает что-то по-другому. И предположим, что finally будет закрывать поток. Просто попробуйте создать простой для чтения пример для будущих читателей.

  • Управление, нет try/catch.
  • Код с 1 try/catch для каждого необходимого места.
  • Код с только 1 try/catch, окружающим весь блок кода.

Что принято считать лучшей практикой и почему?


Сценарий 1

Код без try/catch, просто для управления.

    BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
    bufferedReader.close();

Сценарий 2

Код с блоком try/catch для каждого отдельного места.

    BufferedReader bufferedReader = null;
    try {
        bufferedReader = new BufferedReader(new FileReader("somepath"));
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    String line;
    try {
        while ((line = bufferedReader.readLine()) != null) {
            Object object = new Object();
            this.doSomething(object);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        bufferedReader.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

Сценарий 3

Код с 1 try/catch, окружающим весь блок кода.

    try {
        BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            Object object = new Object();
            this.doSomething(object);
        }
        bufferedReader.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
4b9b3361

Ответ 1

Вы должны указать свои попытки/уловы на основе следующих критериев:

  • Вам нужно делать разные вещи на основе того, откуда исходило исключение?
  • Вам нужно делать разные вещи, на основе которых было выбрано исключение?
  • какой код нужно пропустить (он же "недопустим" ), когда выбрано данное исключение?

ответ на эти вопросы позволит вам определить подходящую область для любого блока try/catch.

Ответ 2

Я поставил бы как можно меньше в try-catch.

Это позволяет очень легко перемещать фрагменты кода в отдельные методы, которые являются хорошей практикой кодирования (подчиняясь принципу единой ответственности, см. книгу "Чистый код: руководство по гибкому программному мастерству" Роберта К. Мартина).

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

Сценарий 2 кажется немного экстремальным, хотя, так как метод довольно мал, сценарий 3 кажется лучшим выбором.

Однако вам нужно иметь свой "закрытый" оператор в блоке finally.

Ответ 3

Это вопрос мнения. Я видел каждый из этих шаблонов.

Образец 1 хорош только тогда, когда ваш метод может выкидывать экскременты и иметь что-то в ручке вызывающей цепи. Это часто бывает желательным. Однако, поскольку вызов close не находится в finally block, он не может быть вызван. По крайней мере, используйте блок try-finally.

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

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

В псевдокоде этот вариант шаблона 3 лучше:

Declare Streams, connections, etc.
try
    Initialize streams, connections, etc,
    Do work.
catch (optional)
    Catch and handle exceptions.
    Do not simply log and ignore.
finally
    Close connections and streams in reverse order.
    Remember, closing these objects can throw,
        so catch exceptions the close operation throws.
End.

Если вы используете Java 7, используйте try-with-resources:

try (BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"))) {
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
}

У вас IOException пузырь до абонента.

Ответ 4

Вы должны пойти с третьим сценарием.

Если bufferedReader попадает в исключение, а затем при создании во втором сценарии, то вы пытаетесь readLine() на нем, это приведет к другому исключению. Нет смысла создавать несколько исключений для одной и той же проблемы.

Вы также должны закрыть ваш bufferedReader в блоке finally.

BufferedReader bufferedReader;
try {
    bufferedReader = new BufferedReader(new FileReader("somepath"));
    String line;
    while ((line = bufferedReader.readLine()) != null) {
        Object object = new Object();
        this.doSomething(object);
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (bufferedReader != null)
        bufferedReader.close(); 
}

Ответ 5

Я думаю, что это похоже на то, сколько кода вводить в метод. Попробуйте написать try/catch/finally, который занимает не более одного экрана. Я хочу сказать, что это не проблема для обертывания всего тела метода в блок try {}, но вы должны разделить этот код на несколько методов, если он стал слишком длинным.

Ответ 6

Вы, например, с одним try/catch, не имеют смысла, потому что вы просто печатаете трассировку стека и продолжаете - уже зная, что это будет сбой. Вы также можете попробовать/поймать всю партию или добавить throws SomeException в подпись метода и позволить вызывающему методу решить, что пошло не так.

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

Ответ 7

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

Ответ 8

Не сценарий 2. Если создается конструктор FileReader или BufferedReader, то bufferedReader будет иметь значение null, но следующий try/catch будет выполняться. Поэтому вы получите исключение (uncaught) в bufferedReader.readLine - исключение NullPointerException. Между сценариями 1 и 3 мне обычно нравится еще 3, потому что он не требует, чтобы вызывающий вызывал. BTW, вам не нужно поймать FileNotFoundException явно, потому что он наследует от IOException и, следовательно, блокирует блокировку обоих.

Ответ 9

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

  • Должен ли я обрабатывать неожиданный результат здесь или я должен распространять его на более высоком уровне?
  • С какими неожиданными результатами я должен справиться?
  • Как с ними справиться?

В 95% случаев я не продвигаюсь дальше первой точки, поэтому я просто распространяю ошибки.

Для обработки файлов я использую try-with-resources для повторного запуска IOException с throw new RuntimeException(e).

Ответ 10

jtahlborn уже имеет правильный ответ.

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

Другим возможным сценарием являются вложенные блоки try-catch.

Рассмотрим:

BufferedReader bufferedReader = new BufferedReader(new FileReader("somepath"));
try {
        String line;

        while ((line = bufferedReader.readLine()) != null) {
            Object object = new Object();
            try {
               this.doSomething(object);
            } catch (InvalidArgumentException iae) {
               throw new RuntimeErrorException("Failed to process line " + line + ", iae);
            } catch (ParserWarning e) {
               e.printStackTrace();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        bufferedReader.close();
    }