I really don't get the point in using nested try-catch blocks. They are difficult to read and sometimes non pretty straightforward. For instance:
try {
// do something
}
catch ( [exception_1] e) {}
catch ( [exception_2] e) {}
catch ( [exception_3] e) {}
The code above is more readable and I can understand what it does - if an exception occurs it can be handled by one of the catch blocks. But if I use the nested form:
try {
try {
try {
// Do something for try-block 3
}
catch ( [exception_1] except_1) {};
// Do something for try-block 2
}
catch ( [exception_2] except_2) {};
// Do something for try-block 1
}
catch ( [exception_3] except_3) {}
The code above is a mess, but it achieves exactly the same of the first code. Or it doesn't? Help me figure this out.
CodePudding user response:
OK - a bit contrived but demonstrates the point that the two try-catch structures are different - dependent on the actually implementation (this may be exactly what @KosztDojscia was pointing out so then consider this answer a duplicate) :
public class Main
{
public static class Exception1 extends Exception { }
public static class Exception2 extends Exception { }
public static class Exception3 extends Exception { }
public static void main(String[] args) {
int i = 0;
// "messy" structure
try {
try {
try {
i = 3; if (i == 3) throw new Exception1();
} catch (Exception1 e1) { i = 300; }
i = 4; if (i == 4) throw new Exception2();
} catch (Exception2 e2) { i = 400; }
i = 5; if (i == 5) throw new Exception3();
} catch (Exception3 e3) { i = 500; }
System.out.println(i);
// "clean" structure
try {
i = 3; if (i == 3) throw new Exception1();
i = 4; if (i == 4) throw new Exception2();
i = 5; if (i == 5) throw new Exception3();
} catch (Exception1 e1) { i = 300; }
catch (Exception2 e2) { i = 400; }
catch (Exception3 e3) { i = 500; }
System.out.println(i);
}
}
Prints:
500
300
CodePudding user response:
Nested try-catch blocks are very useful for setting up auto-closed resources that may require some intermediate processing at the stages in-between, in place of listing all resources in the outer try block:
try(var autoClosedA = initResourceA()) {
var somevar = someprocessingfor(autoClosedA);
try(var autoClosedB = initResourceB(somevar)) {
// Some processing
}
} catch (SomeException | OtherException ex) {
logger.error("Failed to handle XYZ on params: " someparam, ex);
throw ex;
}
Note that you don't necessarily need to make the code untidy with exception handling at each level as later JDKs allow re-use of the same exception handler as shown above. You don't even need the catch in multiple methods as you can keep all application error reporting in the highest level of your application.
CodePudding user response:
Emm, it depends on how you write code. If some code will be used for example...
try {
try {
-->in here<--
try {
// Do something for try-block 3
}
catch ( [exception_1] except_1) {};
// Do something for try-block 2
}
catch ( [exception_2] except_2) {};
// Do something for try-block 1
}
catch ( [exception_3] except_3) {}
then if exception_1 is raised, won't be caught. If everything will be used inside third try, then there is no difference.