Должны ли блокировать java try так сильно, насколько это возможно?

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

Я не уверен, что это разумный вывод.

Рассмотрим две реализации ниже функции, обрабатывающей указанный текстовый файл.

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

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

Какова наилучшая практика для обработки исключений в funcion, где в его определении могут быть выбраны несколько исключений?

Этот код содержит весь код обработки в блоке try:

void processFile(File f)
{
  try
  {
    // construction of FileReader can throw FileNotFoundException
    BufferedReader in = new BufferedReader(new FileReader(f));

    // call of readLine can throw IOException
    String line;
    while ((line = in.readLine()) != null)
    {
      process(line);
    }
  }
  catch (FileNotFoundException ex)
  {
    handle(ex);
  }
  catch (IOException ex)
  {
    handle(ex);
  }
}

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

void processFile(File f)
{
  FileReader reader;
  try
  {
    reader = new FileReader(f);
  }
  catch (FileNotFoundException ex)
  {
    handle(ex);
    return;
  }

  BufferedReader in = new BufferedReader(reader);

  String line;
  while (true)
  {
    try
    {
      line = in.readLine();
    }
    catch (IOException ex)
    {
      handle(ex);
      break;
    }

    if (line == null)
    {
      break;
    }

    process(line);
  }
}

Ответ 1

Основная предпосылка здесь неверна: размер блока try не влияет на производительность. На производительность влияет фактическое увеличение исключений во время выполнения и независимое от размера блока try.

Тем не менее, сохранение небольших блоков try может привести к улучшению программ.

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

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

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

Конечно, есть & hellip; исключения (извините!) в соответствии с этими рекомендациями. Например, в некоторых случаях очень специфические отчеты об ошибках могут быть проблемой безопасности.


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

Блок

A try создает запись в таблице исключений, связанной с этим методом. В этой таблице есть ряд счетчиков инструкций источника, тип исключения и команда назначения. Когда возникает исключение, эта таблица проверяется, есть ли запись с подходящим типом и диапазон, включающий инструкцию, которая вызвала исключение. Если это так, выполнение переходит к соответствующему номеру назначения.

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

Ответ 2

Мне сказали, что есть некоторые накладные расходы при использовании механизма try-catch Java.

Совершенно верно. И там накладные вызовы методов тоже. Но вы не должны поместить весь свой код в один метод.

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

Для меня первое проще всего прочитать.

Ответ 3

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

Ответ 4

Это преждевременная оптимизация в худшем случае. Не делай этого.

"Мы должны забыть о небольшой эффективности, скажем, около 97% времени: преждевременная оптимизация - это корень всего зла" - Кнут.

Ответ 5

для второго метода очень мало пользы. в конце концов, если вы можете успешно открыть файл, но не прочитать его, то с вашим компьютером что-то не так. таким образом, зная, что исключение io из метода readLine() очень редко используется. также, как вы знаете, разные исключения вызывают разные проблемы (FileNotFoundException и т.д.)

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

Ответ 6

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

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

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

Ответ 7

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