Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use the InputSupplier or OutputSupplier api of Guava?

Tags:

java

io

guava

I am new to the guava library, and I am quite confused with the InputSupplier and OutputSupplier. According to the javadoc, they are just factories for InputStream and OutputStream respectively. However, I don't see anything quite useful of these two interface, could anyone show me a example why I should use these two APIs besides for higher abstraction?

like image 263
jlchen Avatar asked Mar 09 '11 22:03

jlchen


2 Answers

The main benefit of both of these interfaces is that they allow library code to control the whole lifecycle of the actual input/output objects. Guava's utilities never close an InputStream or OutputStream that you pass in directly, because that might not be what you want to happen. Even if they did, you'd still need try/finally to deal with errors creating objects. The suppliers are a sort of lazy callback that allow the actual objects to be created, used and closed all in one go without you having to do a lot of ugly try/finally and error handling.

For an example, just look at the code it takes to copy one file to another (with the actual copying and stream closing code minimized using Guava utilities):

File in = ...
File out = ...
FileInputStream inStream = new FileInputStream(in);
boolean threw = true;
try {
  /*
   * Note how two try/finally blocks are needed here, in case creating 
   * outStream fails.
   */
  FileOutputStream outStream = new FileOutputStream(out);
  try {
    ByteStreams.copy(inStream, outStream);
    threw = false;
  } finally {
    Closeables.close(outStream, threw);
  }
} finally {
  Closeables.close(inStream, threw);
}

Then look at the code if you use suppliers instead:

File in = ...
File out = ...
ByteStreams.copy(Files.newInputStreamSupplier(in), 
    Files.newOutputStreamSupplier(out));
like image 187
ColinD Avatar answered Oct 22 '22 11:10

ColinD


With Guava's InputSupplier / OutputSupplier, you do not have to handle yourself the various IOExceptions thrown when instantiating FileInputStreams / FileOutputStreams. Guava will automatically handle these exceptions for you when it calls the InputSupplier.getInput() / OutputSupplier.getOutput() factory methods.

By encapsulating the input / output construction in these factory interfaces, you defer their instantiation, and thus defer the moment you will need to handle the IOException / FileNotFoundException they may throw. In fact, you defer it so much, that it's Guava that handles it for you.

You can then replace

    FileInputStream inputStream = null;
    try {
        inputStream = new FileInputStream(file);
    } catch (FileNotFoundException ex) {
        throw new RuntimeException(ex);
    }

    doSomething(inputStream);

with

    InputSupplier<FileInputStream> inputStreamSupplier = Files.newInputStreamSupplier(file);

    doSomething(inputStreamSupplier);

Edit: also see ColinD's answer, on how Guava may close these inputs / outputs for you when it controls their whole lifecycle (that is, when it used an InputSupplier / OutputSupplier to obtain them).

like image 45
Etienne Neveu Avatar answered Oct 22 '22 10:10

Etienne Neveu