fge
fge

Reputation: 121800

Why does PrintStream extend FilterOutputStream and not OutputStream?

System.out and System.err are both PrintStreams; and PrintStream extends FilterOutputStream.

From the FilterOutputStream's javadoc:

This class is the superclass of all classes that filter output streams. These streams sit on top of an already existing output stream (the underlying output stream) which it uses as its basic sink of data, but possibly transforming the data along the way or providing additional functionality.

The class FilterOutputStream itself simply overrides all methods of OutputStream with versions that pass all requests to the underlying output stream. Subclasses of FilterOutputStream may further override some of these methods as well as provide additional methods and fields.

(emphasis mine)

FilterOutputStream itself extends OutputStream.

I am at a loss here. Is there any reason why PrintStream needs to extend FilterOutputStream instead of OutputStream?

Sample code appreciated...

Upvotes: 4

Views: 533

Answers (3)

Eng.Fouad
Eng.Fouad

Reputation: 117655

FilterOutputStream applies the composition pattern where it delegates all the calls to its instance variable out:

/* The underlying output stream to be filtered. */
protected OutputStream out;

FilterOutputStream also has default implementations for the abstract class OutputStream:

public void write(int b) throws IOException {
    out.write(b);
}

public void write(byte b[]) throws IOException {
    write(b, 0, b.length);
}

public void write(byte b[], int off, int len) throws IOException {
    if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
        throw new IndexOutOfBoundsException();

    for (int i = 0 ; i < len ; i++) {
        write(b[off + i]);
    }
}

public void flush() throws IOException {
    out.flush();
}

public void close() throws IOException {
    try {
      flush();
    } catch (IOException ignored) {
    }
    out.close();
}

Now, any class including PrintStream can extend FilterOutputStream and override the appropriate methods. Note that they still need to delegate their calls to out. For example PrintStream#flush():

public void flush() {
    synchronized (this) {
        try {
            ensureOpen();
            out.flush();
        }
        catch (IOException x) {
            trouble = true;
        }
    }
}

Upvotes: 2

nanofarad
nanofarad

Reputation: 41281

The PrintStream must implement various filters, handling character encodings, and most ultimately, printing non-character data as characters.

The general contract of FilterOutputStream fits this best, so that is the class used.

Upvotes: 1

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Any higher level Stream that needs to filter the input or output of a nested lower-level Stream, needs to first extend FilteredOutputStream, and the same is true for InputStreams. So it makes sense that all of the higher-level OutputStreams extend the FilteredOutputStream class, in other words, all Streams that allow for and in fact require the nesting of other Streams to function, must extend this class.

I don't know what the class does internally, but I imagine it somehow massages the data to allow the higher level streams to be able to make sense out of them. To know more, I'm guessing that you're going to have to delve into the source code.

Upvotes: 0

Related Questions