Java – Why is close() implemented in InputStream/OutputStream

abstractionjava

It make sense to see close() as non-core functionality of stream objects. This is the reason this method is placed in interface Closeable. One evidence is that class ByteArrayInputStream does not require the close() operation.

public abstract class InputStream implements Closeable {}

public abstract class OutputStream implements Closeable, Flushable {}

Based on the above definitions my observation is that interface Closeable should not be implemented by abstract class InputStream/OutputStream; it has to be left to concrete sub-classes (like class FileInputStream) to implement it.

enter image description here

Do you think my understanding is correct?

Best Answer

Just my two cents. The goal of this answer is to give some thoughts and attract more answers, not trying to sound like definitive or even informative.


Why are streams abstract base classes instead of interfaces?

  • It is possible to define a strictly minimal interface.
    • Typically this consists of: read, write, seek, tell (returns current file position), get length, truncate (reduce file size), close.
  • However, to make the stream implementation convenient to use, a lot of helper methods on the class would be needed.
    • Without these helper methods, it would make the programming language impractical, because it would then be too troublesome to use streams as a fundamental feature of the standard library.
    • These helper methods make use of the minimal interface.
    • Typically, default (standard) implementations can be provided for these helper methods, that would completely satisfy the needs most of the time.
    • Therefore, abstract base classes are used to provide these default helper method implementations to improve the usability of the standard library.

Is the close() method fundamental to the operation of streams?

Contrary to your point of view, I would argue that streams that do not require closing is the minority, rather than majority.

  • File system handles
  • Operating-system owned resources, such as:
    • Sockets
    • Pipes
    • Operating-system managed shared memory (as opposed to JVM-managed memory)
  • Database connections

To put it bluntly,

  • It appears that array-backed streams are the only kind of streams that do not require explicit closing.

Does the cost-benefit analysis favor the inclusion of the close() method into the stream interface?

It seems so. For streams that do not require explicit closing, it is harmless to require it to provide a trivial close() method that does nothing.

Similar observation can be found in the C# language, where it is common to see interfaces that subtype from IDisposable.


Would the failure to include the close() method in the stream interface cause extraordinary harm to implementations that require it?

Yes. Not having it on the interface, or splitting it out to a second Closeable interface would cause extraordinary harm.

In the first code snippet below, suppose InputStream does not contain the close() method. Here is what the code would look like:

public void parseAndCloseStream(InputStream strm) throws IOException
{
    if (strm == null) { /* ... to avoid NPE inside finally */ }
    try
    {
        // read from stream
    }
    finally
    {
        if (strm instanceof Closeable)
        {
            Closeable c = (Closeable)strm;
            c.close();
        }
    }
}

In other words, because the omission implies that "not every InputStream is a Closeable", any consumer of any InputStream instance now has the additional responsibility to check whether the instance is indeed Closeable.

The try-with pattern would then also require more code, because you cannot use an InputStream there unless you can cast it into a Closeable.


Is it a violation of Interface Segregation Principle?

No.

  • If a method is fundamental to the operation for the majority of implementation, it makes sense to require it.
  • Likewise, if a method is cohesive with the rest of the methods in that interface (i.e. common-sense for its inclusion), it is not a violation.

Specifically, Interface Segregation Principle does not require:

  • Does not require an interface to be minimal; even though there are benefits for keeping an interface small and simple.
  • Does not require one to separate out all orthogonal facets of an interface, if doing so will cause more harm than good (great inconvenience).