Java должен попробовать блоки быть ограниченным по объему максимально плотно?

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

Я не так уверен, что это - разумное заключение.

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

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

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

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

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

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);
  }
}

Этот содержит только методы, которые выдают исключения в блоках попытки:

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);
  }
}
40
задан Iain Samuel McLean Elder 13 April 2010 в 23:13
поделиться

7 ответов

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

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

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

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

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

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


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

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

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

.
45
ответ дан 27 November 2019 в 01:43
поделиться

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

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

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

На мой взгляд, первый вариант легче всего читать.

11
ответ дан 27 November 2019 в 01:43
поделиться

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

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

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

1
ответ дан 27 November 2019 в 01:43
поделиться

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

3
ответ дан 27 November 2019 в 01:43
поделиться

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

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

2
ответ дан 27 November 2019 в 01:43
поделиться

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

0
ответ дан 27 November 2019 в 01:43
поделиться

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

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

1
ответ дан 27 November 2019 в 01:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: