Вопрос

Хорошо, я сделал следующее (имена переменных были изменены):


FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...

}
catch (IOException e)
{
    ... handle error ...
}
finally
{
    if (fis != null)
        fis.close();
}

Недавно я начал использовать FindBugs, что говорит о том, что я неправильно закрываю потоки.Я решаю посмотреть, можно ли что-нибудь сделать с помощью блокаfinally{}, а затем вижу, о да, close() может выдать исключение IOException.Что людям здесь делать?Библиотеки Java выдают слишком много проверенных исключений.

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

Решение

Для Java 7 и выше попробовать с ресурсами должен быть использован:

try (InputStream in = new FileInputStream(file)) {
  // TODO: work
} catch (IOException e) {
  // TODO: handle error
}

Если вы застряли на Java 6 или ниже...

Этот шаблон позволяет избежать возни с нулевой:

    try {
        InputStream in = new FileInputStream(file);
        try {
            // TODO: work
        } finally {
            in.close();
        }
    } catch (IOException e) {
        // TODO: error handling
    }

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

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

Это должно сделать что-то вроде следующего, зависит от того, выбрасываете ли вы или проглатываете исключение IOException при попытке закрыть поток.

FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...


}
catch (IOException e)
{
    ... blah blah blah ...
}
finally
{
    try
    {
        if (fis != null)
            fis.close();
    }
    catch (IOException e)
    {
    }
}

Вы можете использовать попробовать с ресурсами добавлена ​​функция JDK7.Он создан именно для борьбы с такого рода вещами

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

В документации говорится:

Заявление Try-with-resources гарантирует, что каждый ресурс будет закрыт в конце заявления.

Вы также можете использовать простой статический вспомогательный метод:

public static void closeQuietly(InputStream s) {
   if (null == s) {
      return;
   }
   try {
      s.close();
   } catch (IOException ioe) {
      //ignore exception
   }
}

и используйте это из своего блокаfinally.

Добавить особо нечего, кроме очень незначительного стилистического предложения. Канонический пример самодокументируемого кода применяется в этом случае - дайте описательное имя переменной игнорируемой IOException что ты должен уловить close().

Итак, ответ кальмара выглядит следующим образом:

public static void closeQuietly(InputStream s) {
   try {
      s.close();
   } catch (IOException ignored) {
   }
}

В большинстве случаев я считаю, что это просто лучше нет чтобы перехватить исключения ввода-вывода, и просто используйте try-finally:

final InputStream is = ... // (assuming some construction that can't return null)
try {
    // process is
    ...
} finally {
    is.close();
}

За исключением FileNotFoundException, вы, как правило, не можете "обойти" IOException.Единственное, что остается сделать, — это сообщить об ошибке, и обычно вы обрабатываете ее дальше по стеку вызовов, поэтому я считаю, что лучше распространить исключение.

С IOException является проверенным исключением, вам придется объявить, что этот код (и любой из его клиентов) throws IOException.Это может быть слишком шумно, или вы не захотите раскрывать детали реализации использования ввода-вывода.В этом случае вы можете обернуть весь блок обработчиком исключений, который обертывает IOException в RuntimeException или абстрактный тип исключения.

Деталь: Я знаю, что приведенный выше код поглощает любое исключение из try блокировать, когда close операция в г. finally блок производит IOException.Я не думаю, что это большая проблема:как правило, исключение из try блок будет тот же IOException что вызывает close потерпеть неудачу (т.IO довольно редко работает нормально, а затем выходит из строя в момент закрытия).Если это вызывает беспокойство, возможно, стоит «заглушить» закрытие.

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

try {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
} catch(IOException exc) {
    // kernel panic
}

Это работает, потому что вызов close во второй раз не имеет никакого эффекта.

Это зависит от гуавы Закрываемые предметы, но при желании можно написать собственный метод closeQuietly, как показано кальмар (смотрите также серг10).

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

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

private void work() throws IOException {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
}

public void workAndDealWithException() {
    try {
        work();
    } catch(IOException exc) {
        // kernel panic
    }
}

На основе http://illegalargumentException.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html (на ссылку Макдауэлла).

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

Поэтому вместо этого где-то в javaIO будет вспомогательный метод, который вы можете импортировать, он, вероятно, будет использовать «закрываемый» интерфейс, а также блок.Внутри этого вспомогательного метода try {closable.close() } catch (IOException ex){ //blah} определяется раз и навсегда, и тогда вы сможете писать

 Inputstream s = ....;
 withClosable(s) {
    //your code here
 }

Вас беспокоит в первую очередь получение чистого отчета от FindBugs или наличие работающего кода?Это не обязательно одно и то же.Ваш исходный код в порядке (хотя я бы избавился от лишнего if (fis != null) проверьте, так как OutOfMemoryException иначе бы его выбросили).FileInputStream имеет метод финализатора, который закроет поток в том маловероятном случае, если вы действительно получите исключение IOException в процессе обработки.Просто не стоит усложнять код, чтобы избежать крайне маловероятного сценария:

  1. вы получаете исключение IOException и
  2. это происходит так часто, что вы начинаете сталкиваться с проблемами невыполненной работы финализатора.

Редактировать: если вы получаете так много исключений IOException, что у вас возникают проблемы с очередью финализатора, то вам предстоит жарить гораздо большую рыбу!Речь идет о приобретении чувства перспективы.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top