I am using try-with-resources, introduced in Java 7. This program downloads several HTTP resources and compresses them.
import java.io.*;
import java.net.*;
import java.util.zip.GZIPOutputStream;
class Main {
private static byte[] downloadAndCompress(URL url) throws IOException {
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try(
Closeable closeConnection = () -> connection.disconnect();
OutputStream gzipOutput = new GZIPOutputStream(byteOutput);
) {
connection.connect();
byte[] buffer = new byte[1024];
int bytesRead;
while (0 <= (bytesRead = connection.getInputStream().read(buffer))) {
gzipOutput.write(buffer, 0, bytesRead);
}
}
return byteOutput.toByteArray();
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++) {
URL url = new URL("http://example.com?" + i);
try {
downloadAndCompress(url);
// TODO: do something with result
} catch (IOException e) {
System.err.println("Failed to download " + url + ": " + e);
}
}
}
}
I wondered what would happen if (1) the request failed and (2) writing the gzip trailer exceeded available heap memory.
So I rewrote downloadAndCompare
to test:
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
try(
Closeable closeConnection = () -> connection.disconnect();
OutputStream gzipOutput = new GZIPOutputStream(byteOutput) {
public void close() { throw new OutOfMemoryError(); }
};
) {
throw new IOException("failed to download");
}
Running it yields
Failed to download http://example.com?0: java.io.IOException
Failed to download http://example.com?1: java.io.IOException
Failed to download http://example.com?2: java.io.IOException
Failed to download http://example.com?3: java.io.IOException
Failed to download http://example.com?4: java.io.IOException
Failed to download http://example.com?5: java.io.IOException
Failed to download http://example.com?6: java.io.IOException
Failed to download http://example.com?7: java.io.IOException
Failed to download http://example.com?8: java.io.IOException
Failed to download http://example.com?9: java.io.IOException
It appears that try-with-resources suppresses all Throwables encountered in closing resources, be they OutOfMemoryError, InterruptedException, or StackOverflowError.
I read that it is a very bad thing to continue after OOM and other errors happen.
How does that reconcile with this language construct? Is ignoring OOM fine? Is try-with-resource safe to use?