Закрытие ресурса, возвращаемого из метода

У меня есть вспомогательный класс со статическим методом, который возвращает поток:

public static InputStream getDocument(File file) throws IOException {
    ZipFile zipFile = new ZipFile(file);
    return zipFile.getInputStream(zipFile.getEntry("entry"));
}

Другой класс обращается к этому методу и использует возвращенный поток:

InputStream is = MyClass.getDocument(new File(str));

Мой код работает.


Однако согласно документации Java мне следует закрыть ресурс:

Ресурс — это объект, который должен быть закрыт после того, как программа закончит работу с ним. Оператор try-with-resources гарантирует, что каждый ресурс будет закрыт в конце оператора.

Но когда я реализую try-with-resources:

public static InputStream getDocument(File file) throws IOException {
    try (ZipFile zipFile = new ZipFile(file);) {
        return zipFile.getInputStream(zipFile.getEntry("entry"));
    }
}

or try-finally:

public static InputStream getDocument(File file) throws IOException {
    InputStream is = null;
    try {
        ZipFile zipFile = new ZipFile(docx);
        is = zipFile.getInputStream(zipFile.getEntry("entry"));
        return is;
    } finally {
        is.close();
    }
}

Я получаю исключение:

java.io.IOException: Stream closed

Как сделать так, чтобы ресурс был закрыт, после его использования?


person Evgenij Reznik    schedule 17.12.2020    source источник
comment
вызывающая сторона отвечает за закрытие ресурса   -  person fantaghirocco came to Rome    schedule 17.12.2020
comment
@tkruse Как это дубликат этого вопроса?   -  person Mark Rotteveel    schedule 20.02.2021
comment
Ответ на связанный вопрос также отвечает на вопрос, заданный здесь, даже если вопросы немного отличаются.   -  person tkruse    schedule 20.02.2021


Ответы (2)


Обычно вызывающая сторона отвечает за закрытие/освобождение ресурсов.
Вы можете использовать конструкции try-with-resource или try-finally вне метода следующим образом. :

try (InputStream is = getDocument(aFile) {
    //… do your stuff
}

Если я могу дать вам совет, напишите его в документации метода:

/**
  * The caller is required to close the returned {@link InputStream}
  */
public static InputStream getDocument(File file) throws IOException
person fantaghirocco came to Rome    schedule 17.12.2020
comment
Я заметил, что SonarQube квалифицировал это как ошибку, что мой ресурс не был закрыт непосредственно в методе. Вот почему мне было интересно... - person Evgenij Reznik; 17.12.2020
comment
Кажется, это ложное срабатывание в SonarQube. Я видел похожую проблему несколько дней назад - person fantaghirocco came to Rome; 17.12.2020
comment
Если вы, ребята, говорите об этом, jira.sonarsource.com/browse/SONARJAVA-2060 это уже должно быть исправлено - person dreamcrash; 17.12.2020

Из аналогичного вопроса Закрывает ли поток источник BufferedReader?: можно использовать функцию потоков onClose() для закрытия базовый ресурс:

static Stream<String> toStream(BufferedReader br){
    return br.lines().onClose(asUncheckedAutoCloseable(br));
}


static Runnable asUncheckedAutoCloseable(AutoCloseable ac) {
    return () -> {
        try {
            ac.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

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

person tkruse    schedule 20.02.2021