System.out закрыт?Могу ли я открыть это снова? - PullRequest
19 голосов
/ 20 января 2012

Я помогал другу написать некоторый код Java, который мало знает о Java.Поэтому я написал ему несколько вспомогательных функций, чтобы легко сделать что-то немного странное в его глазах.Одной из них является функция, которая записывает строку в OutputStream.Взгляните:

public void write(String txt, OutputStream out) {
    PrintWriter printer = new PrintWriter(out);
    printer.print(txt);
    printer.close();
}

Теперь вы можете легко использовать это по-разному, чтобы писать, где вы хотите.Например, вы можете сделать это:

(new StreamHelper()).write("Hello Test", System.out);

Делая это, я обнаружил, что впоследствии System.out.println() больше ничего не записывает в оболочку.Поэтому я думаю, что, возможно, printer.close() автоматически также закрыл System.out, и мне интересно, как его активировать, чтобы я мог использовать его после завершения этой функции.

Верно ли мое предположение?(Как я мог узнать, не спрашивая здесь?)

Как я могу продолжать использовать System.out после вызова функции write()?

Существуют ли лучшие способы написания такихвспомогательная функция?

Ответы [ 7 ]

20 голосов
/ 20 января 2012

Общий контракт для закрытия OutputStream:

public void close () throws IOException Закрывает этот выходной поток и освобождает все системные ресурсы, связанные с этим потоком.Общий контракт закрытия заключается в том, что он закрывает выходной поток.Закрытый поток не может выполнять операции вывода, и не может быть повторно открыт .

PrintStream '

public void close () Закрыть поток.Это делается путем очистки потока и затем закрытия основного выходного потока .

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

Даже если в вашем случае может показаться целесообразным закрыть поток-оболочку, на самом деле это не нужноВы закрываете поток, открытый где-то еще.

Короче говоря:

public void write(String txt, OutputStream out) {
    PrintWriter printer = new PrintWriter(out);
    printer.print(txt);
    printer.flush();
    //it is very unpolite to close someone else's streams!
    //printer.close();
}

Да, и, кстати, вы можете изменить имя функции на print вместо write.

10 голосов
/ 21 мая 2014

Как и другие говорили, поток должен быть закрыт там, где он был открыт.Тем не менее, вы можете написать фасад, чтобы защитить поток от закрытия:

3 голосов
/ 26 августа 2018

Если вы хотите попробовать вывод на консоли JVM, вам лучше получить экземпляр консоли с System.console(). А затем получите метод PrintWriter с console.writer(). После использования PrintWriter вы можете закрыть его. На основании описания консоли JavaDoc,

Вызов close() для объектов, возвращаемых reader() и writer() не закроет основной поток этих объектов.

Вы можете делать это снова и снова. Не нужно беспокоиться о возобновлении потока.

3 голосов
/ 20 января 2012

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

Необходим вызов flush().Обратите внимание, что я делаю == проверку, поскольку ссылки будут идентичны, если вы вызовете этот метод write с аргументом System.out.

public void write(String txt, OutputStream out) {
    PrintWriter printer = new PrintWriter(out);
    printer.print(txt);
    printer.flush();

    if(out != System.out) {
        printer.close();
    }
}

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

Если вы хотите сохранить абстракцию (как намекнул @Urs), сделайте следующее.Но я не вижу смысла в этом сверхинжиниринге

public void write(String txt, OutputStream out) {
    PrintWriter printer = new PrintWriter(out);
    printer.print(txt);
    printer.flush();
}

public void close(OutputStream out) {
    out.close();
}
3 голосов
/ 20 января 2012

System.out - это PrintStream, поэтому приведенный выше код буквально не имеет никакого преимущества перед простым вызовом System.out.print напрямую. Причина, по которой он больше не пишет, заключается в том, что close фактически закрыл System.out.

Если это для регистрации, изучите log4j для своего друга или помогите ему изучить его. Log4j хорошо справляется с ситуациями, когда вам необходимо одновременно выполнять запись в файловый поток, стандартный вывод и т. Д.

2 голосов
/ 20 января 2012

Делай то, что предлагает Стас Курилин.

Как правило, потоки должны быть закрыты стороной, которая их открыла / создала.

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

2 голосов
/ 20 января 2012

Давайте посмотрим на это с точки зрения вызывающей стороны.

У вызывающей стороны есть OutputStream своего рода, и он вызывает метод с именем write().После завершения вызова вызывающая сторона обнаруживает, что поток был закрыт.

На мой взгляд, ваш write() метод просто не должен вызывать printer.close().Последний закрывает поток, предоставленный вызывающей стороной, и, вероятно, не соответствует ожиданиям вызывающей стороны.

Если вам нужно очистить поток, вы можете использовать flush().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...