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?
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));
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With