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

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

В Rational Application Developer (RAD на основе eclipse) под программным анализатором я вижу комментарий для обзора кода (в разделе Performance = > Memory), в котором говорится: "Избегайте выражения throw внутри finally".

Как определить, влияет ли определение в блоке finally на производительность?

введите описание изображения здесь

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

     } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (final IOException ex) {
                throw ex;
            }
        }
    }

Мне просто интересно, как это может повлиять на память и производительность?

4b9b3361

Ответ 1

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

Так как блоку try-finally разрешено бросать IOException в этом случае, здесь лучший способ его написать:

try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get("file.txt"))) {
  /* Work with `bufferedReader` */
}

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

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

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

Предполагается, что вы используете файловый ввод-вывод, но одна и та же структура "try-with-resources" будет работать над тем, что реализует AutoCloseable (потоки, объекты SQL и т.д.).

Ответ 2

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

Две причины не бросать исключение в блок finally:

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

  • Когда ваш обычный поток управления прерывается для исключения, закрытого при закрытии, вы можете позволить какой-то преходящий сбой ввода-вывода (который у вас не контролируется и который не влияет на вашу бизнес-логику ) препятствует выполнению какой-либо полезной работы (например, это может привести к откату текущей транзакции). Это может зависеть от того, какой ресурс задействован; может быть, есть случай, когда вы действительно можете провалить все это, если закрытие не происходит чисто, но для многих распространенных случаев (например, JDBC) нет веских оснований для ухода.

Использование try-with-resources успешно исключает возможность маскировки исключений. Однако, если логика try завершится без какого-либо исключения, она позволяет распространять все, что бросается на закрытие. Поскольку это дополнение языка, Oracle должен придерживаться самого консервативного подхода, просто знайте, что он делает, когда вы его используете.

Ответ 3

Идеальное решение:

try (BufferedReader bufferedReader = ...) {
  //do stuff
}

Но, возможно, вы находитесь в java 1.6:

BufferedReader bufferedReader = null;
try{
  bufferedReader = ...;
  //do stuff
} finally {
  if (bufferedReader != null) {
    try {
      bufferedReader.close();
    } catch (final IOException ex) {
      logger.error("Problem while cleaning up.", ex);
    }
  }
}

Ответ 4

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

Хорошо, если у вас есть методы очистки для каждого объекта A и B отдельно, в котором вы обрабатываете блокировку finally catch. Вы можете вызвать оба метода очистки объектов. Исключения из каждой очистки объекта независимо обрабатываются.

Ответ 5

В приведенном фрагменте кода нет смысла указывать оператор throw. Исключение было бы уже вызвано методом bufferedReader.close(). Блок catch должен просто обрабатывать его, а не бросать другое исключение. На самом деле, в то время как ловить брошенное исключение, безусловно, справедливо в блоке finally, я действительно не могу думать о допустимой причине, чтобы исключить исключение в блоке finally.

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

Что касается конкретного случая, когда это было бы вредно, что-то вроде этого приходит в голову с моей головы. Если у вас был еще один метод, выполняющий очистку в вашем блоке finally, например FileOutputStream.close(), и первый из них сделал ошибку, второй никогда не запустится, поскольку оператор throw завершит обработку блока. В этот момент вы будете испытывать утечку ресурсов.

Итак, чтобы подвести итог, try/catch отлично работают в блоке finally, но следует избегать использования инструкции throw для эффективности, а также непреднамеренных последствий (утечки памяти).