Created
December 13, 2021 14:53
-
-
Save ktul/4efa279329d3eb583bbc517857e2aa4c to your computer and use it in GitHub Desktop.
Try-with-resources example and an equivalent old-style implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.IOException; | |
| import java.util.Arrays; | |
| import java.util.stream.Collectors; | |
| class TryWithResources { | |
| public static void main(String[] args) { | |
| System.out.println("with resources:"); | |
| withResource(); | |
| System.out.println("\nold-style:"); | |
| oldStyle(); | |
| System.out.println("\nwrong old style:"); | |
| wrongOldStyle(); | |
| } | |
| // Some example of a try-with-resources. | |
| private static void withResource() { | |
| try (var a = new Closeable("a"); var b = new Closeable("b")) { | |
| a.fail(); | |
| } catch (Exception e) { | |
| handleException(e); | |
| } finally { | |
| System.out.println("finally"); | |
| } | |
| } | |
| // This method has the same behaviour as withResource(), but doesn't use resources | |
| // Remarks: | |
| // - The implementation details and bytecode might differ. | |
| // - This was not tested with shared resources, so there might be some synchronization missing. | |
| private static void oldStyle() { | |
| try { | |
| var a = new Closeable("a"); | |
| var b = new Closeable("b"); | |
| try { | |
| a.fail(); | |
| } catch (Exception e) { | |
| try { | |
| b.close(); | |
| } catch (Exception e2) { | |
| e.addSuppressed(e2); | |
| } | |
| try { | |
| a.close(); | |
| } catch (Exception e2) { | |
| e.addSuppressed(e2); | |
| } | |
| throw e; | |
| } | |
| b.close(); | |
| a.close(); | |
| } catch (Exception e) { | |
| handleException(e); | |
| } finally { | |
| System.out.println("finally"); | |
| } | |
| } | |
| // One could easily but wrongly assume this is what happens during a try-with-resources. | |
| // But here's what's wrong: | |
| // - Exceptions are ignored, resources are not closed and finally might not be executed. | |
| // Worst case: | |
| // - b.close #1 throws | |
| // -> a.close #1 is never reached -> a is not closed | |
| // -> (if the exception handler exits: throw e is never reached -> e is ignored) | |
| // -> b.close #2 is called on a possibly closed b | |
| // -> b.close throws again | |
| // -> a.close #1 is never reached -> a is never closed | |
| // -> (if the exception handler exits: finally is never reached) | |
| private static void wrongOldStyle() { | |
| var a = new Closeable("a"); | |
| var b = new Closeable("b"); | |
| try { | |
| a.fail(); | |
| } catch (Exception e) { | |
| try { | |
| b.close(); // #1 | |
| a.close(); // #1 | |
| } catch (IOException e2) { | |
| handleException(e2); | |
| } | |
| handleException(e); | |
| } finally { | |
| try { | |
| b.close(); // #2 | |
| a.close(); // #2 | |
| } catch (IOException e2) { | |
| handleException(e2); | |
| } | |
| System.out.println("finally"); | |
| } | |
| } | |
| private static void handleException(Exception e) { | |
| var suppressed = Arrays.stream(e.getSuppressed()) | |
| .map(Throwable::getMessage) | |
| .collect(Collectors.joining(", ")); | |
| var message = "caught exception from " + e.getMessage() + " with " | |
| + (suppressed.isEmpty() ? "nothing" : suppressed) | |
| + " suppressed"; | |
| System.out.println(message); | |
| } | |
| private final static class Closeable implements AutoCloseable { | |
| private final String name; | |
| Closeable(String name) /*throws IOException*/ { | |
| System.out.println(name + ".new"); | |
| this.name = name; | |
| // throw new IOException(name + ".new"); // alternative when constructor throws | |
| } | |
| public void fail() throws IOException { | |
| System.out.println(name + ".fail"); | |
| throw new IOException(name + ".fail"); | |
| } | |
| public void close() throws IOException { | |
| System.out.println(name + ".close"); | |
| throw new IOException(name + ".close"); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment