Закройте сканер, связанный с System.in

У меня есть Scanner, связанный с System.in. Теперь, после использования Scanner, я должен закрыть его, так как оставлять его открытым — плохая практика кодирования. Но если я закрою Scanner, я также закрою System.in! Может ли кто-нибудь сказать мне, как я могу закрыть Scanner, не закрывая System.in (если есть какой-либо способ).


person JavaNewbie_M107    schedule 03.01.2013    source источник
comment
stackoverflow.com/questions/5919143/, надеюсь, это может быть вам полезно. Я все еще смотрю, реализует ли System.in возможность закрытия. Если нет, они вы в чистоте.   -  person paul jerman    schedule 03.01.2013
comment
Обратите внимание, что вы можете защитить поток с помощью декоратор.   -  person McDowell    schedule 03.01.2013
comment
Да, System.in реализует closeable.   -  person JavaNewbie_M107    schedule 03.01.2013
comment
@pauljerman System.in является InputStream и поэтому реализует AutoClosable, см. документы.   -  person jlordo    schedule 03.01.2013
comment
поцарапайте это, не закрывайте, вы сканер. я опубликую ответ   -  person paul jerman    schedule 03.01.2013
comment
@McDowell извините за кражу вашего ответа. Не видел, пока не написал то же самое XD   -  person paul jerman    schedule 03.01.2013
comment
@pauljerman - не проблема   -  person McDowell    schedule 03.01.2013
comment
возможный дубликат закрытия BufferedReader и System.in   -  person Raedwald    schedule 22.06.2015
comment
Доктор, мне больно, когда я это делаю! ... Тогда не делайте этого.   -  person kaya3    schedule 03.03.2020


Ответы (5)


Один из вариантов — обернуть поток System.in в поток CloseShieldInputStream, который предотвратит его закрытие. Тогда ваш читатель будет использовать поток CloseShieldInputStream, а не необработанный поток System.in.

Вот API для класса: http://commons.apache.org/io/apidocs/org/apache/commons/io/input/CloseShieldInputStream.html

person paul jerman    schedule 03.01.2013
comment
вы также можете создать свою собственную незакрывающуюся оболочку для потока System.in - person paul jerman; 03.01.2013

Самое простое — не закрывать Scanner, если вы не хотите закрывать основной поток.

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

person Peter Lawrey    schedule 03.01.2013
comment
Это работает, требуя от кода ЗНАТЬ, что он разговаривает с системой или, по крайней мере, с чем-то, что не должно быть закрыто. Рекомендация Пола Джерманса CloseShieldInputStream позволяет коду игнорировать этот факт и просто обрабатывать его как любой другой InputStream и пытаться закрыть его по завершении. То, что здесь просто, на самом деле зависит от контекста. - person candied_orange; 26.11.2016
comment
@candied_orange вам не следует закрывать поток, которым вы не владеете (что, учитывая отсутствие строгого понятия владения в Java, примерно означает, что вы не открывали). Если вы получили поток откуда-то еще, не закрывайте Сканер. - person Andy Turner; 12.10.2018
comment
@AndyTurner, это работает. Если вы хотите следовать этому правилу и по-прежнему иметь возможность широкого использования, поищите отверстие в среднем шаблоне - person candied_orange; 12.10.2018

Вместо того, чтобы добавлять классы щитов и тому подобное, просто оставьте хороший комментарий и

        @SuppressWarnings("resource")

Этого достаточно. И я не вижу много недостатков в этом подходе. Не забудьте комментарий.

person mist    schedule 06.07.2014
comment
? Это может подавить предупреждение, но не помешает вам получить IOException: Stream closed при попытке использовать System.in после закрытия сканера. - person derHugo; 14.12.2018
comment
@derHugo Я думаю, что они имеют в виду не закрывать сканер и подавлять предупреждения об этом аннотацией и добавлять поясняющий комментарий. - person bkis; 15.01.2019

У меня есть смутные воспоминания о странных, не поддающихся диагностике проблемах, связанных с использованием одного и того же Scanner из System.in дважды, поэтому я использую это (хотя вам, вероятно, следует использовать только один сканер на время программы):

static String input() {
    try {
        return new Scanner(System.in).nextLine();
    } catch (NoSuchElementException e) {
        throw e;
    }
}

По какой-то причине это работает без предупреждений, тогда как если я не сделаю ловушку, Eclipse будет жаловаться Resource leak: '<unassigned Closeable value>' is never closed.

person Blrp    schedule 06.11.2015
comment
Вы просто избегаете предупреждения, путая здесь анализ кода Eclipse :) Сканер по-прежнему никогда не закрывается (не то, чтобы вы должны :)) - person john16384; 28.02.2017

Согласно API для InputSteam «Метод close для InputStream ничего не делает», поэтому, поскольку System.in является экземпляром InputStream, вам не нужно беспокоиться о том, что для него будет вызван метод close().

person Ted McLeod    schedule 06.11.2015
comment
Хотя ясно, что это не так. Если я открою Scanner на System.in, закрою его, а затем открою другой и попытаюсь использовать его (например, nextLine()), я получу NoSuchElementException. - person Blrp; 06.11.2015
comment
Хотя close() действительно ничего не делает в стандартной реализации абстрактного InputStream, это не означает, что это верно для всех его подклассов! Если бы это было правдой, метод был бы бесполезен. - person Jiri Tousek; 08.01.2016
comment
InputStream — это абстрактный класс. Подклассы могут и должны что-то делать, когда они представляют ресурс (например, стандартный ввод), который необходимо закрыть после использования. Конечно, это можно было бы прояснить в InputStream.close(), но ваш вывод неверен. - person dimo414; 26.02.2016
comment
Этот ответ совершенно неверен, и я думаю, что его нужно удалить. - person aristotll; 16.09.2020