Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does PrintStream.close() end up getting called twice?

Somewhat to my surprise, the following code prints out "Close" twice. Running through the debugger, it seems MyPrintStream.close() calls super.close(), which ends up calling MyPrintStream.close() again.

    
import java.io.*;

public class PrintTest
{
    static class MyPrintStream extends PrintStream
    {
        MyPrintStream(OutputStream os)
        {
            super(os);
        }

        @Override
        public void close()
        {
            System.out.println("Close");
            super.close();
        }
    }

    public static void main(String[] args) throws IOException
    {
        PrintStream ps = new MyPrintStream(new FileOutputStream(File.createTempFile("temp", "file")));
        ps.println("Hello");
        ps.close();
    }
}

Why is this happening? Should I not be extending PrintStream?

like image 951
Simon Nickerson Avatar asked May 12 '09 13:05

Simon Nickerson


People also ask

Do I need to close PrintStream?

No. It is not require to close other components.

How do I close PrintStream?

The close() method of PrintStream Class in Java is used to close the stream. Closing a stream deallocates any value in it or any resources associated with it. The PrintStream instance once closed won't work. Also a PrintStream instance once closed cannot be closed again.

What does PrintStream mean in Java?

A PrintStream adds functionality to another output stream, namely the ability to print representations of various data values conveniently. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested via the checkError method.

What is the difference between PrintStream and PrintWriter?

The primary difference is that PrintStream writes raw bytes in the machine's native character format, and PrintWriter converts bytes to recognized encoding schemes. Thus, files created with PrintWriter are more compatible across different platforms than files created with PrintStream .


1 Answers

If you look at your code in a debugger and set a breakpoint in the close() method, it'll reveal the stacktraces of who is calling your close() method:

  1. your main method
  2. sun.nio.cs.StreamEncoder$CharsetSE.implClose() line 431

the complete stacktrace for the latter looks like:

PrintTest$MyPrintStream.close() line: 20    
sun.nio.cs.StreamEncoder$CharsetSE.implClose() line: 431 [local variables unavailable]  
sun.nio.cs.StreamEncoder$CharsetSE(sun.nio.cs.StreamEncoder).close() line: 160 [local variables unavailable]    
java.io.OutputStreamWriter.close() line: 222 [local variables unavailable]  
java.io.BufferedWriter.close() line: 250 [local variables unavailable]  
PrintTest$MyPrintStream(java.io.PrintStream).close() line: 307  
PrintTest$MyPrintStream.close() line: 20    
PrintTest.main(java.lang.String[]) line: 27 

Sadly though I can't tell why StreamEncoder would call back into your PrintStream though, as my IDE doesn't have a source attachment for sun.nio.cs.StreamEncoder :( This is JDK 6 btw, if that matters.

By the way, if you are asking this question because you noticed that custom code in your close() method is running twice, you should really be checking if this.closing. PrintStream.close() sets this to true (and the class's comments state /* To avoid recursive closing */ ).

like image 74
matt b Avatar answered Sep 23 '22 02:09

matt b