Должны ли блоки java try быть ограничены настолько, насколько это возможно? - PullRequest
40 голосов
/ 14 апреля 2010

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

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

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

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

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

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

Этот содержит весь код обработки в блоке 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);
  }
}

Ответы [ 7 ]

45 голосов
/ 14 апреля 2010

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

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

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

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

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

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


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

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

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

11 голосов
/ 14 апреля 2010

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

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

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

Мне первое легче всего читать.

3 голосов
/ 14 апреля 2010

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

2 голосов
/ 14 апреля 2010

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

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

1 голос
/ 14 апреля 2010

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

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

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

1 голос
/ 14 апреля 2010

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

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

0 голосов
/ 14 апреля 2010

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

...