Multiple IOException subclasses not being caught when in try catch block
<p>I'm using the following method to download images from a server to serve in an Android application.</p>

<pre><code>public static void downloadToFile(File file, URL url, int connectTimeout, 
        int readTimeout) throws IOException {
    InputStream in = null;
    OutputStream out = null;
    try {
        URLConnection ucon = url.openConnection();
        ucon.setConnectTimeout(connectTimeout);
        ucon.setReadTimeout(readTimeout);

        in = ucon.getInputStream();
        out = new FileOutputStream(file);
        byte[] buffer = new byte[BUFFER_SIZE];
        int count = 0;
        while ((count = in.read(buffer)) != -1) {
            out.write(buffer, 0, count);
        }
        out.flush();
    } finally {
        if (in != null) {
            in.close();
        }
        if (out != null) {
            out.close();
        }
    }
}
</code></pre>

<p>When a file has been deleted from the server but I try to download it anyway, I receive a FileNotFoundException, which is perfectly valid. In my application, the call to this method is wrapped in a try catch handling both IOException and Exception so I can just continue on.</p>

<p>The problem is that in the Android Developer Console I've received a few crash reports and the FileNotFoundException seems to be ignoring the catch blocks and force closing the app.</p>

<pre><code>java.io.FileNotFoundException: http://foo.org/1234.jpg
at   org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:1162)
at com.package.IOUtil.downloadToFile(Unknown Source)
</code></pre>

<p>The Unknown Source is because of Proguard but I can force the exception when testing by putting in non-existant file URLS which does throw the exception. When I test on my phone (SGS2 2.3.3) and tablet (TF101 3.2) the try catch block does catch the exception. The stack trace below points to the URL#getInputStream() as what is throwing the exception but that doesn't explain why it isn't being caught for some (only a few).</p>

<pre><code>java.io.FileNotFoundException: http://foo.org/1234.jpg
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:521)
at com.package.IOUtil.downloadToFile(IOUtil.java:142)
</code></pre>

<p>I've also had the same problem with a SocketException from the same method/callee not being caught.</p>

<pre><code>java.net.SocketTimeoutException: Connection timed out
at org.apache.harmony.luni.platform.OSNetworkSystem.connect(Native Method)
at dalvik.system.BlockGuard$WrappedNetworkSystem.connect(BlockGuard.java:357)
at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:204)
at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:437)
at java.net.Socket.connect(Socket.java:1002)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.&lt;init&gt;(HttpConnection.java:75)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.&lt;init&gt;(HttpConnection.java:48)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection$Address.connect(HttpConnection.java:322)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnectionPool.get(HttpConnectionPool.java:89)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getHttpConnection(HttpURLConnectionImpl.java:285)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.makeConnection(HttpURLConnectionImpl.java:267)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1018)
at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:512)
at com.package.IOUtil.downloadToFile(Unknown Source)
</code></pre>

<p>The downloading is done in a background thread if that matters.</p>

<p>Am I missing something? Could it be phone specific, or Proguard (even though it's caught by almost everybody else)?</p>

<p>Edit: Code that catches</p>

<pre><code>private void download(List&lt;URL&gt; urls, int attempts) {
    List&lt;URL&gt; failedDownloads = new ArrayList&lt;URL&gt;();
    for (URL url : urls) {
        if (isInterrupted()) {
            return;
        }

        String imageName = Util.getImageName(url);
        File cacheFile = cache.getCacheFile(imageName);
        try {
            // Bad downloads often don't throw an IOException but
            // leave the file with a length of 0.
            if (cacheFile.length() == 0) {
                Util.safeDelete(cacheFile);
            }

            if (!cacheFile.exists()) {
                IOUtil.downloadToFile(cacheFile, url);

                if (cacheFile.length() == 0) {
                    //See above
                    Util.safeDelete(cacheFile);
                    failedDownloads.add(url);
                } else {
                    if (putToCache) {
                        cache.get(imageName);
                    }
                    handler.sendEmptyMessage(0);
                }
            } else {
                // Exists already, move it to cache
                if (putToCache) {
                    cache.get(imageName);
                }
            }
        } catch (IOException ioe) {
            Util.safeDelete(cacheFile);
            failedDownloads.add(url);
        } catch (Exception e) {
            // Continue on to next download - don't bother trying this
            // URL again.
        }
    }

    if (!failedDownloads.isEmpty() &amp;&amp; attempts &lt; maxAttempts) {
        attempts++;
        download(failedDownloads, attempts);
    }
}
</code></pre>

<p>Util.safeDelete is just a delete wrapped in a try catch so that shouldn't be related.</p>
