From fd2287bbe0ebd9924b39408e6d68d17451afdeeb Mon Sep 17 00:00:00 2001 From: "gu.martinm@gmail.com" Date: Wed, 2 Jul 2014 12:21:16 +0200 Subject: [PATCH] Try-with-resources example and thoughts --- .../src/de/example/tryfinally/Main.java | 81 +++++++++++++++ .../example/tryfinally/TryWithResourcesMain.java | 65 ++++++++++++ .../Try-With-Resources-Java/under_the_scenes.txt | 109 +++++++++++++++++++++ 3 files changed, 255 insertions(+) create mode 100644 Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/Main.java create mode 100644 Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/TryWithResourcesMain.java create mode 100644 Allgemeines/Try-With-Resources-Java/under_the_scenes.txt diff --git a/Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/Main.java b/Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/Main.java new file mode 100644 index 0000000..ef6df85 --- /dev/null +++ b/Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/Main.java @@ -0,0 +1,81 @@ +package de.example.tryfinally; + +public class Main { + static String result; + + public static void main(final String[] args) { + System.out.println("Calling go"); + final String st = returnAndFinally(); + System.out.println("Back from go: " + st); + System.out.println("Surprise!! " + result); + + try { + System.out.println(noCatchAndFinally()); + } catch (final Exception e) { + System.out.println("Second catch."); + e.printStackTrace(); + } + } + + public static String returnAndFinally() { + result = "NOK"; + + try { + messingAround(); + return result; + } + catch (final Exception ex) { + System.out.println("Entered catch: " + result); + result = "OK"; + //This is the return statement that this method will execute in case of any Exception class or subclass is thrown. + return result; + } + finally { + //You will not see FINALLY in the "Back from go:" statement. + //From stackoverflow: + //http://stackoverflow.com/questions/421797/what-really-happens-in-a-try-return-x-finally-x-null-statement. + // * Code before return statement is executed + // * Expression in return statement is evaluated + // * finally block is executed + // * Result evaluated in step 2 is returned + + result = "FINALLY"; + System.out.println("Entered finally: " + result); + //NEVER USE return in finally block because you can loose the stack if some exception is thrown from the try block!!! + //You finish with this return instead of the previous one. + //http://stackoverflow.com/questions/48088/returning-from-a-finally-block-in-java + //return result; + } + } + + public static void messingAround() throws Exception { + throw(new Exception()); + } + + + public static String noCatchAndFinally() throws Exception { + try { + messingAround(); + return "You will not see me"; + } + finally { + try + { + //Catching this exception does not swallow the previous one (if there was one) + messingAroundReturns(); + } + catch (final Exception e) { + System.out.println("First catch."); + e.printStackTrace(); + } + //NEVER USE return in finally block because you can loose the stack if some exception is thrown from the try block!!! + //http://stackoverflow.com/questions/48088/returning-from-a-finally-block-in-java + // return + // "Do not do this. You are loosing the exception thrown by messingAround method!!!"; + } + } + + public static void messingAroundReturns() throws Exception { + throw(new Exception()); + } +} diff --git a/Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/TryWithResourcesMain.java b/Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/TryWithResourcesMain.java new file mode 100644 index 0000000..96dc4f1 --- /dev/null +++ b/Allgemeines/Try-With-Resources-Java/src/de/example/tryfinally/TryWithResourcesMain.java @@ -0,0 +1,65 @@ +package de.example.tryfinally; + +public class TryWithResourcesMain { + + public static void main(final String[] args) { + System.out.println("BEGIN FIRST EXAMPLE"); + System.out.flush(); + + try (final ResourceFirst resourceOne = new ResourceFirst(); + final ResourceSecond resourceTwo = new ResourceSecond()) + { + resourceTwo.doSomething(); + resourceOne.doSomething(); + } catch (final Exception e) { + System.out.println("Exception from some resource: "); + System.out.flush(); + e.printStackTrace(); + System.out.flush(); + } + + System.out.println("END FIRST EXAMPLE"); + System.out.flush(); + + } + + public static class ResourceFirst implements AutoCloseable + { + public ResourceFirst() { + + } + + public void doSomething() { + System.out.println("ResourceFirst: doSomething"); + System.out.flush(); + throw new RuntimeException("ResourceFirst doSomething RuntimeException!!!"); + } + + @Override + public void close() throws Exception { + System.out.println("I am the close of ResourceFirst"); + System.out.flush(); + throw new Exception("ResourceFirst close Exception!!!"); + } + } + + + public static class ResourceSecond implements AutoCloseable + { + public ResourceSecond() { + + } + + public void doSomething() { + System.out.println("ResourceSecond: doSomething"); + System.out.flush(); + } + + @Override + public void close() throws Exception { + System.out.println("I am the close of ResourceSecond"); + System.out.flush(); + throw new Exception("ResourceSecond close Exception!!!"); + } + } +} diff --git a/Allgemeines/Try-With-Resources-Java/under_the_scenes.txt b/Allgemeines/Try-With-Resources-Java/under_the_scenes.txt new file mode 100644 index 0000000..203fe0c --- /dev/null +++ b/Allgemeines/Try-With-Resources-Java/under_the_scenes.txt @@ -0,0 +1,109 @@ +output from example: + +BEGIN FIRST EXAMPLE +ResourceSecond: doSomething +ResourceFirst: doSomething +I am the close of ResourceSecond +I am the close of ResourceFirst +Exception from some resource: +java.lang.RuntimeException: ResourceFirst doSomething RuntimeException!!! + at de.example.tryfinally.TryWithResourcesMain$ResourceFirst.doSomething(TryWithResourcesMain.java:35) + at de.example.tryfinally.TryWithResourcesMain.main(TryWithResourcesMain.java:13) + Suppressed: java.lang.Exception: ResourceSecond close Exception!!! + at de.example.tryfinally.TryWithResourcesMain$ResourceSecond.close(TryWithResourcesMain.java:62) + at de.example.tryfinally.TryWithResourcesMain.main(TryWithResourcesMain.java:14) + Suppressed: java.lang.Exception: ResourceFirst close Exception!!! + at de.example.tryfinally.TryWithResourcesMain$ResourceFirst.close(TryWithResourcesMain.java:42) + at de.example.tryfinally.TryWithResourcesMain.main(TryWithResourcesMain.java:14) +END FIRST EXAMPLE + + + +So, it is nicer than C# because you can see the hidden exceptions. +As in C# it keeps running the close methods even if some of them throw exception!!! + +SO, THE BEST WAY TO CLOSE DEVICES IN JAVA IS USING TRY-WITH-RESOURCES!!!!! +OTHERWISE YOU ARE GOING TO WRITE LOADS OF CODE IF YOU WANT TO DO THE SAME!!!! + + +1 .BEFORE JAVA 7; some Java SMART developers (the most of them do not even know they have to release +resources...) always did something like this: + + MyResourceOne resourceOne; + MyResourceTwo resourceTwo; + try { + *** WHATEVER YOU DO WITH YOUR RESOURCES *** + } finally { + if (resourceOne != null) { + closeQuietly(resourceOne); + } + if (resourceTwo != null) { + closeQuietly(resourceTwo); + } + } + + private void closeQuietly(final Closeable resource ) { + try { + if (resource != null) { + resource.close(); + } + } catch(final IOException e) { + logger.error( "Exception while closing resource ", e); + } + } + +IMHO swallowing exceptions is not nice... Perhaps for some particular things it could be interesting +but in general NEVER SWALLOW EXCEPTIONS LIKE THAT!!! + + +2. Other ways I have seen: + + MyResourceOne resourceOne; + MyResourceTwo resourceTwo; + try { + *** WHATEVER YOU DO WITH YOUR RESOURCES *** + } finally { + if (resourceOne != null) { + resourceOne.close(); + } + if (resourceTwo != null) { + resourceTwo.close(); + } + } + +The problem with this way is, if resourceOne.close() throws exception I am not going to call resourceTwo.close() :( +Even if this guy says the opposite: http://stackoverflow.com/a/18496449 (IMHO THAT ANSWER SUCKS!!!!) + + +3. Before Java 1.7 this was the only "nice" way (IMHO) + + + MyResourceOne resourceOne = new MyResourceOne(); + + try { + *** WHATEVER YOU DO WITH YOUR RESOURCE ONE *** + MyResourceTwo resourceTwo = new MyResourceTwo(); + try { + *** WHATEVER YOU DO WITH YOUR RESOURCE TWO *** + } finally { + resourceTwo.close(); + } + } finally { + resourceOne.close(); + } +It is really close to RAII C++. I am always closing resources and I do not swallow exceptions :) +You could achieve this solution through using multiple methods (instead of one with nested try/finally blocks); +for example one nice solution would be with the Execute Around idiom and closures. + +IMHO since Java 1.7 and the TRY-WITH-RESOURCES there is no doubt what everybody should use. Besides, we +do not need anymore the Execute Around idiom AFAIU. +But perhaps with the Execute Around idiom the code in some case could be clearer. For simple things I guess +the best is the TRY-WITH-RESOURCE; for complicated ones (see Spring JDBC) the Exceute Around idiom would be better +(I guess) + +http://stackoverflow.com/questions/12552863/correct-idiom-for-managing-multiple-chained-resources-in-try-with-resources-bloc +http://stackoverflow.com/a/12665271 <---- This answer is the best. I do not wonder that guy comes from C++ :) +http://stackoverflow.com/a/18496449 <---- This answer sucks. + +http://stackoverflow.com/questions/341971/what-is-the-execute-around-idiom +http://stackoverflow.com/questions/481446/throws-exception-in-finally-blocks <--- Swallowing exceptions... :/ \ No newline at end of file -- 2.1.4