Безопасно ли не закрывать Java Scanner, при условии, что я закрываю базовый readable?

#java #java.util.scanner

#java #java.util.scanner

Вопрос:

Если у меня есть метод, который использует reader, и я хочу работать с reader с помощью сканера следующим образом:

 Scanner scanner = new Scanner(reader);
while(scanner.hasNext()) {
    //blah blah blah
}
  

Безопасно ли не закрывать scanner ? В документации говорится, что он «закрывает этот сканер», а затем говорится о закрытии базового readable. Предположим, я не хочу закрывать readable и вместо этого хочу, чтобы вызывающий объект закрылся reader , когда будет готов. Безопасно ли не закрывать scanner здесь?

Ответ №1:

Это зависит от того, от чего вы хотите быть в безопасности.

  • Если вы просто пытаетесь убедиться, что базовый поток закрыт, то подойдет любой подход.

  • Если вы также хотите, чтобы Scanner объект был помечен как закрытый (чтобы все последующие операции с объектом немедленно завершились неудачей), тогда вам следует вызвать Scanner.close() .

Это общий принцип; т. Е. он также применим к различным типам потоков, которые так или иначе выполняют буферизацию в памяти.

Комментарии:

1. Этот ответ соответствует контракту, как определено в документации .

Ответ №2:

Поскольку у меня уже открыт исходный код 🙂 …

close() Метод проверяет, Readable также реализует Closeable ли базовый интерфейс, и если это так, он закрывает его. В вашей ситуации вы говорите, что это не проблема, потому что он будет закрыт позже.

Но close() метод также устанавливает некоторые внутренние флаги, указывающие, что Scanner (и базовый Readable ) закрыты. Многие общедоступные методы сначала проверяют, был ли Scanner закрыт. Таким образом, опасность здесь может заключаться в том, что, возможно, ваш базовый Readable был закрыт, но дальнейшие вызовы Scanner не выдают an немедленно IllegalStateException , а вместо этого завершаются сбоем каким-либо другим способом по мере продолжения.

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

close() Метод также обнуляет свою ссылку на Readable , поэтому, если этого не произойдет, Scanner мусор не будет собран, как только вы бы вызвали его close() .

Я бы позвонил Scanner.close() , если это возможно.

Ответ №3:

Мне также нужно было закрыть Scanner и оставить базовый поток открытым для дальнейшей работы. Что я сделал, так это создал класс, который расширяет BufferedInputStream и переопределяет close() метод с пустым телом. Этот класс я ввел в конструктор Scanner . Таким образом, вы можете вызывать scanner.close() , не закрывая поток. Вам нужно сохранить ссылку на оригинал BufferedInputStream , хотя, но это очевидно.

Ответ №4:

Хорошо, если у вас есть класс Caller и Reader. Вызывающий не должен знать о реализации Reader. В следующем методе reader:

 while scanner has object
   read them ( one object per method's call) 
when objects are done
   close the reader. 
  

Это своего рода шаблон итератора.