2014-01-21 8 views
5

Предположим, что я использую плохо документированную стороннюю библиотеку, для которой нет исходного кода. Один из методов библиотеки принимает InputStream для загрузки различных данных.Ручное закрытие внутри try-with-resource

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

К сожалению, спецификация Java делает (насколько я могу судить) отсутствие упоминания о том, что произойдет, если ресурс закрыт вручную внутри try-with-resource. Кто-нибудь знает?

+0

Вы можете просто попробовать, не так ли? – Fildor

+0

@Fildor Обычно это плохая практика просто «попытаться угадать» вместо того, чтобы смотреть на документацию (даже если там, документ плох). Просто потому, что функция возвращает '1' для' -1', а '1' не делает ее функцией' abs'. – Xenos

+0

@ Xenos Я не имел в виду «попытаться угадать». Я имел в виду «черный ящик». Если документация оставляет желать лучшего, вы хотите узнать как можно больше об этой функции. Поэтому вы будете снимать на нем сложный набор тестов (по крайней мере, я бы). Тогда я бы закодировал что-то стабильное, даже если подозрительная функция ведет себя смешно. И я никогда не говорил «вместо того, чтобы смотреть в документы». BTW: У меня были * встречи, где документы были * неправильными *. – Fildor

ответ

8

Это полностью зависит от реализации самого ресурса. Оператор try-with-resource является «просто» синтаксическим сахаром (но так сладким) для вызова close() в блоке finally (и сохранения исключений и т. Д.).

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

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

try (InputStream input = new FileInputStream(...)) { 
    try (Reader reader = new InputStreamReader(input, ...)) { 
     ... 
    } 
} 

Или с одной примерки с-ресурсов заявление:

try (InputStream input = new FileInputStream(...); 
    Reader reader = new InputStreamReader(input, ...)) { 
    ... 
} 

В обоих случаях будет два finally блоки, так что первый reader.close() называется, то input.close() - но reader.close() закроет input так или иначе.

+0

@MarkoTopolnik: Я добавил и одну версию. Оба работают, но некоторые из них могут найти первое, о чем легче начать рассуждать. –

+0

@MarkoTopolnik: запятая во второй форме была преднамеренной - это попытка использования ресурсов * двух ресурсов *. –

+0

Но он не компилируется, я проверил его. Вы тоже это проверили, и это сработало для вас? Я был бы удивлен, честно говоря, потому что это несовместимо с остальным синтаксисом Java. –

2

Спецификация говорит все, что может: если resource.close() выдает исключение, это исключение будет выбрано из конструкции.

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

0

Вы можете попытаться закрыть его в описании finally.

InputStream stream = null; 
try { 
    stream = new InputStream(); 
    yourMethod(stream); 
} catch (...) { 

} finally { 
    try { 
    stream.close() 
    } catch (IOException ioe) { 
    // can throw IOException while closing closed stream 
    } 
} 
5

Метод close() из Closeable (и, таким образом, из InputStream) требуется для идемпотентным:

Если поток уже закрыт, то применение этого метода не имеет никакого эффекта.

Поэтому безопасно закрыть InputStream более одного раза. Интерфейс

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

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