Обычно, когда вам нужно закрыть ресурс, который вы использовали в Java, вы обращаетесь к надежному блоку finally и закрываете все открытые ресурсы внутри блока finally.

Почему нужно всегда закрывать открытые ресурсы

Например, предположим, что вы используете объект java.sql.Connection для подключения к базе данных, объект java.sql.PreparedStatement для подготовки SQL-запроса и объект java.sql.ResultSet для получения возвращаемого результата из запроса к базе данных.

Естественно, поскольку вы находитесь в идеальной зоне разума, вы должны помнить о закрытии объекта java.sql.Connection , объекта java.sql.PreparedStatement и объекта java.sql.ResultSet в блоке finally, как показано в приведенном ниже фрагменте кода.

Connection con;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
  // your code with database connections
}
catch ( Exception e )
{
  //Catch and handle any exceptions
}
finally
{
  con.close();
  ps.close();
  rs.close();
}

Примечание. Закрытие объекта java.sql.ResultSet не требуется явно (поскольку объект java.sql.ResultSet автоматически закрывается сгенерировавшим его объектом Statement, когда этот объект Statement закрывается, повторно выполняется или используется для извлечения следующего результата из последовательности нескольких результатов согласно документации Java о java.sql.ResultSet ) рекомендуется закрывать объект ResultSet вручную, потому что некоторые драйверы JDBC имеют тенденцию к сбою при автоматическом закрытии объекта ResultSet.

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

Здесь на помощь придет новый оператор try-with-resources, представленный в Java 7.

Использование try-with-resources в основном таково: вы можете объявить все закрываемые объекты ресурсов, которые вы собираетесь использовать, внутри предложения try, и Java позаботится о закрытии ресурсов самостоятельно.

try (   Connection con = getConnection(); PreparedStatement ps = null; ResultSet resultSet = null; )
{
   // your code with database connections
}
catch ( Exception e )
{
   //Catch and handle any exceptions
}
finally
{
   // Instead of closing open resources, you can do anything else in       here
}

Обратите внимание, что с оператором try-with-resources можно использовать только объекты, реализующие java.lang.AutoCloseable. Сюда входят все классы, реализующие java.io.Closeable.

И еще кое-что

Еще одним преимуществом использования инструкции try-with-resources является возможность предотвратить маскирование исключений.

Возьмем следующий пример.

У нас есть myMethod()с обычным блоком try/finally для обработки объектов ресурсов. И у нас есть метод main, который перехватывает исключение, выдаваемое myMethod().

В myMethod() есть два исключения, которые могут быть выброшены.

1. ExceptionType1 выбрасывается в блоке try.

2. ExceptionType2 выдается при попытке закрыть ресурс.

public static void myMethod() throws Exception()
{
  Closeable resource = null;
  try
  {
    // your code which throws ExceptionType1
  }
  finally
  {
    resource.close();
    // an exception of type ExceptionType1 will be thrown when    trying to close the resource
  }
}

И пример, где вы используете вышеуказанный метод.

public static void main(String[] args) {
  try
  {
    myMethod();
  }
  catch( Exception e)
  {
    e.printStackTrace();
  }
}

В приведенном выше сценарии, когда исключение генерируется в блоке try и в блоке finally, блок catch получит только исключение ExceptionType2. То есть ExceptionType1, сгенерированный первым, будет маскирован с помощью ExceptionType2, сгенерированного вторым.

Итак, как нам идентифицировать исключение, вызванное нашим блоком кода?

Здесь нам на помощь приходит оператор try-with-resources. Давайте проанализируем приведенный выше сценарий, используя оператор try-with-resource.

Основное исключение ExceptionType1, которое нам нужно, сначала выбрасывается блоком кода. Затем возникает второе исключение ExceptionType2, когда Java пытается закрыть ресурсы.

Но разница в том, что второе исключение будет подавлено и добавлено к основному исключению ExceptionType1 как подавленноеисключение. представлены в блок catch метода main().

То есть, если мы структурируем наш myMethod(), как показано ниже, исключение, пойманное в блоке catch, будет ExceptionType1 с ExceptionType2, добавленным как подавленное исключение. Таким образом, мы поймаем нужное нам исключение, не маскируя его более поздним исключением.

public static void myMethod() throws Exception()
{
   try ( Closeable resource = null; )
   {
     // your code which throws ExceptionType1
   }
}

Заключение

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

Дополнительные сведения об использовании инструкции try-with-resources и о том, как обрабатываются исключения внутри инструкции try-with-resources, см. на странице