Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning an InputStream from a public method

I have a class where on the one hand, it feels right to return an InputStream from a public method, e.g.

public class MyClass {

    private File _file;

    ...

    public InputStream getInputStream() {
        return new FileInputStream( _file );
    }
}

However, I'm also very cautious about doing this, as it puts the onus on the caller to close this stream. What ways can I potentially avoid this problem?

like image 502
Matt Dunn Avatar asked Nov 16 '12 16:11

Matt Dunn


3 Answers

Depends on why this is a problem in your eyes. If you absolutely must return an InputStream and the file in question is not too large, you could buffer the entire file into a byte array, close the original stream and return new ByteArrayInputStream(buf). Closing a ByteArrayInputStream is not necessary (and in fact has no effect).

However, if it "feels right" to return an InputStream, does it not make sense that the caller should be expecting an InputStream, and all that goes with it, including the necessity of closing the stream when finished?

like image 101
CupawnTae Avatar answered Oct 26 '22 23:10

CupawnTae


Returning InputStream is not intrinsically a bad thing. Now if you want your caller to access the data without being responsible for closing the resource, you can do that:

interface InputReader {
    void readInput(InputStream is);
}
public class MyClass {
    void feed(InputReader ir){
       try(InputStream is=new FileInputStream( _file )){
          ir.readInput(is);
       }
    }
}

The caller specify an instance of InputReader that will receive the closable resource as argument and is no longer responsible for closing it.

MyClass myClass = ... ; //Get the instance
myClass.feed( new InputReader() {
    @Override
    void readInput(InputStream is){
       ... ; // Use at will without closing
    }
});

One should consider to decorate the InputStream before passing it to the InputReader so that .close() throws and exception.

like image 40
Pierre Avatar answered Oct 27 '22 01:10

Pierre


Realistically there's not much you can do without knowing more details about the class. You could provide file processing through methods in MyClass (which requires knowing what the file contents mean) and close the stream when it's empty. Aside from that though, the user of the class is responsible for this object, and you can't really avoid that. Without the capability of destructors, as in C++, you cannot be 100% responsible for any object that you let leave the scope of your class.

What you can do is put a close() method on your class which cleans up any open file handlers, connections, etc., and require the user of the class to be responsible for calling close(). See this question for some discussion of how to use the finalize method to keep track of whether callers are properly closing your class.

like image 41
Chris Hayes Avatar answered Oct 27 '22 00:10

Chris Hayes