Вопрос

Есть ли элегантный способ обработки исключений, которые выбрасываются? finally блокировать?

Например:

try {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}
finally {
   try{
     resource.close();
   }
   catch( Exception ex ) {
     // Could not close the resource?
   }
}

Как избежать try/catch в finally блокировать?

Это было полезно?

Решение

Обычно я делаю это так:

try {
  // Use the resource.
} catch( Exception ex ) {
  // Problem with the resource.
} finally {
  // Put away the resource.
  closeQuietly( resource );
}

В другом месте:

protected void closeQuietly( Resource resource ) {
  try {
    if (resource != null) {
      resource.close();
    }
  } catch( Exception ex ) {
    log( "Exception during Resource.close()", ex );
  }
}

Другие советы

Обычно я использую один из closeQuietly методы в org.apache.commons.io.IOUtils:

public static void closeQuietly(OutputStream output) {
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException ioe) {
        // ignore
    }
}

Если вы используете Java 7 и resource реализует AutoClosable, вы можете сделать это (на примере InputStream):

try (InputStream resource = getInputStream()) {
  // Use the resource.
}
catch( Exception ex ) {
  // Problem with the resource.
}

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

Resource resource = null;
boolean isSuccess = false;
try {
    resource = Resource.create();
    resource.use();
    // Following line will only run if nothing above threw an exception.
    isSuccess = true;
} finally {
    if (resource != null) {
        if (isSuccess) {
            // let close throw the exception so it isn't swallowed.
            resource.close();
        } else {
            try {
                resource.close();
            } catch (ResourceException ignore) {
                // Just swallow this one because you don't want it 
                // to replace the one that came first (thrown above).
            }
        }
    }
}

ОБНОВЛЯТЬ:Я изучил это немного подробнее и нашел отличный пост в блоге от человека, который явно думал об этом больше, чем я: http://illegalargumentException.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html Он идет еще дальше и объединяет два исключения в одно, что, как мне кажется, может оказаться полезным в некоторых случаях.

Начиная с Java 7, вам больше не нужно явно закрывать ресурсы в окончательно вместо этого вы можете использовать блок пытатьсяСинтаксис -с-ресурсами.Оператор try-with-resources — это оператор try, который объявляет один или несколько ресурсов.Ресурс — это объект, который необходимо закрыть после завершения работы программы с ним.Оператор try-with-resources гарантирует, что каждый ресурс будет закрыт в конце оператора.В качестве ресурса можно использовать любой объект, реализующий java.lang.AutoCloseable, включая все объекты, реализующие java.io.Closeable.

Предположим следующий код:

try( Connection con = null;
     Statement stmt = con.createStatement();
     Result rs= stmt.executeQuery(QUERY);)
{  
     count = rs.getInt(1);
}

Если произойдет какое-либо исключение, закрывать метод будет вызываться для каждого из этих трех ресурсов в порядке, противоположном их созданию.Это означает, что метод close будет вызываться сначала для ResultSetm, затем для Statement и в конце для объекта Connection.

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

Источник: https://docs.oracle.com/javase/tutorial/essential/Exceptions/tryResourceClose.html

Игнорирование исключений, возникающих в блоке «finally», обычно является плохая идея если только не знать, какими будут эти исключения и какие условия они будут представлять.В обычном режиме try/finally шаблон использования, try блок переводит вещи в состояние, которого внешний код не ожидает, и finally блок восстанавливает состояние этих вещей до того состояния, которое ожидает внешний код.Внешний код, который перехватывает исключение, обычно ожидает, что, несмотря на исключение, все было восстановлено до исходного состояния. normal состояние.Например, предположим, что некоторый код запускает транзакцию, а затем пытается добавить две записи;блок «finally» выполняет операцию «откат, если не зафиксировано».Вызывающий может быть готов к возникновению исключения во время выполнения второй операции «добавление» и может ожидать, что если он перехватит такое исключение, база данных окажется в том состоянии, в котором она была до попытки выполнения любой операции.Однако если во время отката произойдет второе исключение, могут произойти плохие вещи, если вызывающая сторона сделает какие-либо предположения о состоянии базы данных.Ошибка отката представляет собой главный кризис - тот, который не должен быть обнаружен кодом, ожидающим простого исключения «Не удалось добавить запись».

Лично я склоняюсь к тому, чтобы методfinally перехватывал возникающие исключения и заключал их в «CleanupFailedException», признавая, что такой сбой представляет собой серьезную проблему, и к такому исключению не следует относиться легкомысленно.

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

try {
    ...
    }
catch(package1.Exception err)
   {
    ...
   }
catch(package2.Exception err)
   {
   ...
   }
finally
  {
  }

Но иногда вы не можете избежать этой второй попытки.напримердля закрытия потока

InputStream in=null;
try
 {
 in= new FileInputStream("File.txt");
 (..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
 }
catch(SQLException err)
 {
 //handle exception
 }
finally
 {
 //at the end, we close the file
 if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
 }

Почему вы хотите избежать дополнительного блока?Поскольку блок «finally» содержит «обычные» операции, которые могут вызвать исключение, И вы хотите, чтобы блок «finally» выполнялся полностью, вы ДОЛЖНЫ перехватывать исключения.

Если вы не ожидаете, что блок «finally» выдаст исключение, и вы все равно не знаете, как обработать исключение (вы просто сбрасываете трассировку стека), позвольте исключению всплывать в стеке вызовов (удалите try-catch из «finally»). блокировать).

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

try {
    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }

    try {
        ...
    } catch (Exception ex) {
        ...
    } finally {
        ...
    }
} catch (Exception ex) {
    ...
}

После долгих размышлений я нашел следующий код лучшим:

MyResource resource = null;
try {
    resource = new MyResource();
    resource.doSomethingFancy();
    resource.close(); 
    resource = null;  
} finally {
    closeQuietly(resource)
}

void closeQuietly(MyResource a) {
    if (a!=null)
        try {
             a.close();
        } catch (Exception e) {
             //ignore
        }
}

Этот код гарантирует следующее:

  1. Ресурс освобождается после завершения кода
  2. Исключения, возникающие при закрытии ресурса, не используются без их обработки.
  3. Код не пытается закрыть ресурс дважды, ненужное исключение не будет создано.

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

try{...}
catch(NullArgumentException nae){...}
finally
{
  //or if resource had some useful function that tells you its open use that
  if (resource != null) 
  {
      resource.Close();
      resource = null;//just to be explicit about it was closed
  }
}

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

Вы можете реорганизовать это в другой метод...

public void RealDoSuff()
{
   try
   { DoStuff(); }
   catch
   { // resource.close failed or something really weird is going on 
     // like an OutOfMemoryException 
   }
}

private void DoStuff() 
{
  try 
  {}
  catch
  {
  }
  finally 
  {
    if (resource != null) 
    {
      resource.close(); 
    }
  }
}

Обычно я делаю это:

MyResource r = null;
try { 
   // use resource
} finally {   
    if( r != null ) try { 
        r.close(); 
    } catch( ThatSpecificExceptionOnClose teoc ){}
}

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

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

По сей день у меня не было проблем с использованием этой идиомы.

try {
    final Resource resource = acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
} catch (ResourceException exx) {
    ... sensible code ...
}

Дело сделано.Никаких нулевых тестов.Одиночный улов, включая исключения получения и выпуска.Конечно, вы можете использовать идиому «Выполнить вокруг», и вам нужно будет написать ее только один раз для каждого типа ресурса.

Изменение Resource от лучший ответ к Closeable

Потоки реализуют Closeable Таким образом, вы можете повторно использовать метод для всех потоков.

protected void closeQuietly(Closeable resource) {
    if (resource == null) 
        return;
    try {
        resource.close();
    } catch (IOException e) {
        //log the exception
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top