Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does a local PrintWriter interfere with another local PrintWriter?

In this program, the third string never gets printed. Why?

(This Java program was run on Eclipse Indigo on Ubuntu 10.10.)

import java.io.PrintWriter;

public class Tester
{
    static void nested()
    {
        PrintWriter object2 = new PrintWriter(System.out, true);
        object2.println("second");
        object2.close(); // delete this line to make all strings print
    }

    public static void main(String[] args)
    {
        PrintWriter object1 = new PrintWriter(System.out, true);
        object1.println("first");
        Tester.nested();
        object1.println("third");
        object1.close();
    }
}
like image 479
H2ONaCl Avatar asked Aug 07 '11 09:08

H2ONaCl


2 Answers

By closing the nested PrintWriter, you also close the embedded System.out stream, which seemingly prevents further writes to it (although I would expect an exception really instead of swallowing output).

So the entire problem can be reduced to:

public class Tester {

    public static void main(String[] args) {        
        System.out.println("first");
        System.out.close();
        System.out.println("second");        
    }
}

This too doesn't print anymore after "first", but also doesn't throw an exception. A very quick debugging session shows there's a call to a Sun native function, which is a little harder to debug into.

Update*

This is the culprit: System.out is of type java.io.PrintStream and it contains the following lovely method:

private void write(String s) {
    try {
        synchronized (this) {
            ensureOpen();
            textOut.write(s);
            textOut.flushBuffer();
            charOut.flushBuffer();
            if (autoFlush && (s.indexOf('\n') >= 0))
                out.flush();
        }
    }
    catch (InterruptedIOException x) {
        Thread.currentThread().interrupt();
    }
    catch (IOException x) {
        trouble = true;
    }
}

The ensureOpen() method indeed throws an exception, but it's swallowed here and the trouble flag is set (a well known anti-pattern). This thus silently ignores further writes to the closed stream.

like image 152
Arjan Tijms Avatar answered Nov 09 '22 06:11

Arjan Tijms


From the documentation of close() it says

Closes the stream and releases any system resources associated with it. Closing a previously closed stream has no effect

So my guess is that it is releasing the System.out and hence can't be used again. Also, I added a System.out.println("Finished"); line at the end and it doesn't output anything if a close has been called on System.out in the code. Try it out.

like image 32
Sagar V Avatar answered Nov 09 '22 05:11

Sagar V