I have the following piece of code, and I'm trying to understand how can I correctly handle exception in catch block so both exceptions (mainException and anotherException) are thrown so in case of anotherException we do not lose info from mainException.
Also code smells bad - is this kind of try-catch usage is some kind of anti-pattern? Is there a better/correct way to handle this kind of situations?
try {
-some code-
} catch (RuntimeException mainException) {
try {
-another code-
} catch (Exception anotherException) {
throw anotherException;
} finally {
throw mainException;
}
}
In Java 7, as part of the work on try-with-resources, the Throwable class was extended with support for suppressed exceptions, specifically intended for scenarios like this.
public static void main(String[] args) throws Exception {
try {
throw new RuntimeException("Foo");
} catch (RuntimeException mainException) {
try {
throw new Exception("Bar");
} catch (Exception anotherException) {
mainException.addSuppressed(anotherException);
}
throw mainException;
}
}
Output (stacktrace)
Exception in thread "main" java.lang.RuntimeException: Foo
at Test.main(Test.java:5)
Suppressed: java.lang.Exception: Bar
at Test.main(Test.java:8)
Related
I am considering this from the Java Language Specification:
If the catch block completes abruptly for reason R, then the finally block is executed. Then there is a choice:
If the finally block completes normally, then the try statement
completes abruptly for reason R.
If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).
I have a block as follows:
try {
.. do stuff that might throw RuntimeException ...
} finally {
try {
.. finally block stuff that might throw RuntimeException ...
} catch {
// what to do here???
}
}
Ideally, I would want any RuntimeException thrown in the finally block to escape, only if it would not cause a RuntimeException thrown in the main try block to be discarded.
Is there any way in Java for me to know whether the block that is associated with a finally block completed normally or not?
I'm guessing I could just set a boolean as the very last statement of the main try block (e.g., completedNormally = true. Is that the best way, or is there something better / more standard?
I believe the key is to not lose the original cause if any.
If we look at how try-with-resources behave:
private static class SomeAutoCloseableThing implements AutoCloseable {
#Override
public void close() {
throw new IllegalStateException("closing failed");
}
}
public static void main(String[] args) {
try (SomeAutoCloseableThing thing = new SomeAutoCloseableThing()) {
throw new IllegalStateException("running failed");
}
}
We end up with:
Exception in thread "main" java.lang.IllegalStateException: running failed
at Main.main(Main.java:16)
Suppressed: java.lang.IllegalStateException: closing failed
at Main$SomeAutoCloseableThing.close(Main.java:9)
at Main.main(Main.java:17)
This stack trace is great as we see both exceptions, i.e. we don't lose the running failed one.
Implementing this without try-with-resources, the wrong way:
public static void main(String[] args) {
SomeAutoCloseableThing thing = new SomeAutoCloseableThing();
try {
throw new IllegalStateException("running failed");
} finally {
thing.close();
}
}
We end up with:
Exception in thread "main" java.lang.IllegalStateException: closing failed
at Main$SomeAutoCloseableThing.close(Main.java:9)
at Main.main(Main.java:19)
We don't know that running failed occurred too as we broke the control flow, that's quite bad if you need to debug such a case.
Implementing this without try-with-resources, the right way (in my opinion), is to "log and forget" the exception that occurred in the finally block:
public static void main(String[] args) {
SomeAutoCloseableThing thing = new SomeAutoCloseableThing();
try {
throw new IllegalStateException("running failed");
} finally {
try {
thing.close();
} catch (Exception e) {
LoggerFactory.getLogger(Main.class).error("An error occurred while closing SomeAutoCloseableThing", e);
}
}
}
We end up with:
17:10:20.030 [main] ERROR Main - An error occurred while closing SomeAutoCloseableThing
java.lang.IllegalStateException: closing failed
at Main$SomeAutoCloseableThing.close(Main.java:10) ~[classes/:?]
at Main.main(Main.java:21) [classes/:?]
Exception in thread "main" java.lang.IllegalStateException: running failed
at Main.main(Main.java:18)
Not as good as the try-with-resources approach, but at least we know what actually happened, nothing got lost.
I assume your finally block is doing cleanup. A good way to accomplish such cleanup is to create a class that implements AutoCloseable, so your code can place it in a try-with-resources statement:
class DoStuff
implements AutoCloseable {
public void doStuffThatMightThrowException() {
// ...
}
#Override
public void close() {
// do cleanup
}
}
(Notice that it does not need to be a public class. In fact, it probably shouldn’t be.)
The code in your example would then look like this:
try (DoStuff d = new DoStuff()) {
d.doStuffThatMightThrowException();
}
As for what happens if an exception is thrown during the cleanup: it becomes a suppressed exception. It won’t show up in a stack trace, but you can access it if you really want to (which you probably won’t).
I don't think there is an idiomatic solution to this problem, partly because you normally use finally to clean-up resources disregarding completely if the code that allocated the resource terminated normally or not.
For example you finally close a connection, but the transaction will be rolled back in the catch block or committed as a last statement of the code block wrapped in the try.
Concerning an throwable thrown inside the finally block, you should decide which exception is most important to pass on to the caller. You can ultimately create your own exception which holds reference to both exceptions, in that case you need to declare a variable initialized outside the try and set inside the catch.
For example, in the following code you either complete normally or throw an exception, while having tried a recovery (rolling back a transaction) and tried a clean-up in finally.
Either can fail and you wrap what you think is the most important data in the exception you finally throw.
private void foo() throws SQLException {
Throwable firstCause = null;
try {
conn.prepareStatement("...");
// ...
conn.commit();
} catch (SQLException e) {
firstCause = e;
conn.rollback();
throw e;
} finally {
try {
conn.close();
} catch (Exception e) {
throw new RuntimeException(firstCause);
// or
// throw new RuntimeException(e);
// or
// throw new MyException(e,firstCause);
}
}
}
You could capture the original exception and re-throw it from within finally block.
Code below does just that and the exception thrown out of the method below will have the stacktrace and the cause dictated by the outer RuntimeException.
private void testException() {
RuntimeException originalFailure = null;
try {
throw new RuntimeException("Main exception");
} catch (RuntimeException e) {
originalFailure = e;
} finally {
try {
throw new RuntimeException("Final exception");
} catch (RuntimeException e) {
if (originalFailure != null) {
throw originalFailure;
} else {
throw e; //OR do nothing
}
}
}
}
I wrote an example which depicts my issue.
I have a simple exception:
public class TryToSpeakException extends RuntimeException {
public TryToSpeakException(String message) {
super(message);
}
}
Then I have a chain of methods that invoke each other one by one:
public class TryToSpeak {
public static void speakToPerson1() {
throw new TryToSpeakException("Person 1 don't wanna speak to anyone.");
}
public static void speakToPerson2() {
try {
speakToPerson1();
} catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
}
}
public static void speakToPerson3() {
try {
speakToPerson2();
} catch (Exception e) {
System.out.println("speakToPerson3 caused exception");
e.printStackTrace();
}
}
static void keepSilentToPerson() {
System.out.println("Keeping silent to person 1");
}
public static void communicate() {
try {
speakToPerson3();
keepSilentToPerson(); // Why it reaches this part?
} catch (Exception e) {
System.out.println("Communication exception.");
e.printStackTrace();
}
}
public static void main(String[] args) {
communicate();
}
}
The method from the very 'bottom' throws an exception. In method communicate() after invocation of method speakToPerson3() the execution keeps going.
What i need - is to Stop execution, so that invocation of method keepSilentToPerson() is never reached and gives me the message "Communication exception.".
This is what i get in console now:
speakToPerson2 caused exception
exceptions.TryToSpeakException: Person 1 don't wanna speak to anyone.
at exceptions.TryToSpeak.speakToPerson1(TryToSpeak.java:7)
at exceptions.TryToSpeak.speakToPerson2(TryToSpeak.java:12)
at exceptions.TryToSpeak.speakToPerson3(TryToSpeak.java:22)
at exceptions.TryToSpeak.communicate(TryToSpeak.java:36)
at exceptions.TryToSpeak.main(TryToSpeak.java:46)
Keeping silent to person 1
But if i call speakToPerson2() from my Main method like this:
public static void speakToPerson1() {
throw new TryToSpeakException("Person 1 don't wanna speak to anyone.");
}
public static void speakToPerson2() {
try {
speakToPerson1();
keepSilentToPerson();
} catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
}
}
static void keepSilentToPerson() {
System.out.println("Keeping silent to person 1");
}
public static void main(String[] args) {
speakToPerson2();
}
I get an obvious result:
speakToPerson2 caused exception
exceptions.TryToSpeakException: Person 1 don't wanna speak to anyone.
at exceptions.TryToSpeak.speakToPerson1(TryToSpeak.java:7)
at exceptions.TryToSpeak.speakToPerson2(TryToSpeak.java:12)
at exceptions.TryToSpeak.main(TryToSpeak.java:26)
keepSilentToPerson() is not reached.
What am i doing wrong?
speakToPerson2() is catching the Exception, but you want communicate() to catch it too. Essentially, speakToPerson2() is suppressing the exception, so no other method sees it.
What you need to do is rethrow it (in both speakToPerson2() and speakToPerson3()). This is known as propagating an exception.
I.e.:
public static void speakToPerson2() {
try {
speakToPerson1();
} catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
throw e;
}
}
public static void speakToPerson3() {
try {
speakToPerson2();
} catch (Exception e) {
System.out.println("speakToPerson3 caused exception");
e.printStackTrace();
throw e;
}
}
You need to understand exactly how try-catch work. If any method in the try-catch throws an exception (one that extends/or is Exception in your example), the body of the try-catch will be interrupted to go into the catch clause.
In your case, the method speakToPerson1 will throw a TryToSpeakException. This exception will be forwarded one step above in the method call stack, the method speakToPerson2 in your case. Since the call to speakToPerson1 is surrounded with a try-catch, the catch clause is invoked and System.out.println("speakToPerson2 caused exception"); is executed. Now, the try clause encloses two methods calls, namely speakToPerson1 and keepSilentToPerson. However, since the first method throw the exception, the second is never reached and therefore keepSilentToPerson() will never by called.
Finally, think about the catching of exceptions. If you catch an exception, you are saying that you are going to handle it, by recovering or rethrowing it. If you handle it without rethrowing it, it won't be forwarded to the upper level of your call stack. Beware of this technicality
You can throw the exception after catching it speakTo* methods. This will stop execution of code in methods calling speakTo* and their catch block will be executed.
catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
throw e;
}
You need to propagate your Exceptions to the main class to completely stop the execution of a program.
In the case 1: All your exception will be handled by speakToPerson2 function.
In the case 2: Your exception occurs at the function call of speakToPerson1, so the rest of your code will not execute.
So, inorder to stop the program from running you just have to propagate the exception, using throw keyword, in the catch block of your exception.
Suppose, I have a method:
private void someMethod() {
try {
//Do something here
}
catch (NullPointerException ex) {
System.out.println("error");
}
}
Now, I want to use this method somewhere else:
private void newMethod() {
someMethod();
JOptionPane.showMessageDialog(null, "Exception didn't occur");
}
Now, I want that if exception occurs in someMethod(), then newMethod() will not advance further, I mean, the JOptionPane message will not be shown in this case.
What will be the best way to do that? I have found a way by throwing another NullPointerException in catch block of someMethod() and then handling that from newMethod(). The code below demonstrates that:
private void someMethod() {
try {
//Do something here
}
catch (NullPointerException ex) {
System.out.println("error");
throw new NullPointerException("error");
}
}
private void newMethod() {
try {
someMethod();
JOptionPane.showMessageDialog(null, "Exception didn't occur");
}
catch (NullPointerException ex) {
System.out.println("error");
}
}
But, by this method, I am facing some difficulties for other cases. I guess there are better ways to achieve that. Thanks anyway.
You don't need to handle the exception inside someMethod. Instead you can declare the exception in this method's throws clause (if it is a checked exception) and let newMethod handle it.
private void someMethod() throws SomeCheckedException {
//Do something here
}
In case of NullPointerException, you don't need to do above, as it is an unchecked exception. Don't catch it inside someMethod, instead have try-catch inside newMethod.
It is good practice if your function intend to throw exception make it part of function declaration. So recommendation is to change someMethod() to private void someMethod() throws <exception Name>.
Depends on your requirement you can handle the exception in same method and throw another exception, or re throw same exception and handle it in another function.
In case you are re-throwing the same exception syntax is as follows:
private void someMethod() throws WhateverException {
try {
//Do something here
}
catch (WhateverException e) {
throw e;
}
}
Ok ... So I am learning about exceptions in java and i am currently at throw statements. I throw an exception of Exception class, and then re-throw it from the catch block again to handle it in the main function. But whenever i throw it as Exception class, i always get an Error in the catch block(where i re-throw it to be handled in main).But as soon as i change the thrown and caught Exceptions to some particular Exceptions like NullPointerException, it works!
Error Code:
class ThrowingExceptions {
static boolean enable3dRendering = false;
public static void main(String [] com) {
try {
renderWorld();
}
catch(Exception e) {
System.out.println("Rendering in 2d.");
}
}
static void renderWorld() {
try{
if(!enable3dRendering) {
System.out.println("3d rendering is disabled. Enable 3d mode to render.");
throw new Exception("3d mode Disabled.");
}
else {
System.out.println("The World is Empty!");
}
}
catch(Exception e) {
System.out.println("Please handle the error");
throw e; // It gives me an error here
}
}
}
Working Code:
class ThrowingExceptions {
static boolean enable3dRendering = false;
public static void main(String [] com) {
try {
renderWorld();
}
catch(NullPointerException e) {
System.out.println("Rendering in 2d.");
}
}
static void renderWorld() {
try{
if(!enable3dRendering) {
System.out.println("3d rendering is disabled. Enable 3d mode to render.");
throw new NullPointerException("3d mode Disabled.");
}
else {
System.out.println("The World is Empty!");
}
}
catch(NullPointerException e) {
System.out.println("Please handle the error");
throw e;
}
}
}
Why doesn't it work with Exception class and worked with its subclass??
Note :- The error i get in the error code is Unhandled exception type Exception
Runtime exceptions extend RuntimeException. They don’t have to be handled or declared.
They can be thrown by the programmer or by the JVM.
Checked exceptions have Exception in their hierarchy but not RuntimeException. They
must be handled or declared. They can be thrown by the programmer or by the JVM.
Errors extend the Error class. They are thrown by the JVM and should not be handled or
declared.
When method throws checked exception (1) you should handle or rethow it.
When method throws uncheked exception (2) you can handle or rethrow it, but it's not obligatory.
But whenever i throw it as Exception class, i always get an Error in
the catch block(where i re-throw it to be handled in main)
It means that your method is throwing checked exception which should be handled or rethrowed.
Handling:
public class Main {
public static void main(String[] args) {
try {
throw new Exception();
} catch (Exception e) {
try {
throw new Exception();
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
Rethrowing:
public class Main {
public static void main(String[] args) throws Exception {
try {
throw new Exception();
} catch (Exception e) {
throw new Exception();
}
}
}
In your case:
// You declaring that the caller should handle exception
static void renderWorld() throws Exception {
try {
if(!enable3dRendering) {
System.out.println("3d rendering is disabled. Enable 3d mode to render.");
throw new Exception("3d mode Disabled.");
} else {
System.out.println("The World is Empty!");
}
} catch(Exception e) {
System.out.println("Please handle the error");
// You cannot just throw uncheked exception here
// You should handle it yourself or a caller should do it
throw e;
}
}
Changing
static void renderWorld() { ... }
to
static void renderWorld() throws Exception { ... }
should fix this. This is for the reason that runtime exception are unchecked exceptions.
Would recommend you to read about the Checked and Unchecked exception in details here - Java: checked vs unchecked exception explanation.
It's because they are several Exception classes which are inherited from the class Exception. Each can be throwed, catched but they divide into two groups:
Checked and unchecked exceptions:
An unchecked exception doesn't need to be handled and the
NullPointerException which you tried is from that group, so you don't need to care about it technically.
A checked exception need to be handled every time or it won't
compile, these exceptions are like IOException.
Since the base Exception Object can be checked and unchecked as well the compiler cares about that it should be handled everytime.
If you give it a try and change the NullPointerException to IOException it won't compile either cause it is a Checked Exception. So it was just random, that you exactly find one type of Exception which your code can be work without compile error.
For more info visit my blog post about it:
http://www.zoltanraffai.com/blog/?p=93
Here's the code:
public class Exc {
int x = 2;
public void throwE(int p) throws Excp, Excp2 {
if(x==p) {
throw new Excp();
}
else if(x==(p+2)) {
throw new Excp2();
}
}
}
Here's the handler code:
public class tdExc {
public static void main(String[] args) {
Exc testObj = new Exc();
try {
testObj.throwE(0);
System.out.println("This will never be printed, so sad...");
} catch(Exception Excp) {
System.out.println("Caught ya!");
} catch(Exception Excp2) {
System.out.println("Caught ya! Again!!!!");
} finally {
System.out.println("This will always be printed!");
}
}
}
Excp and Excp2 both extends Exception and have similar code(nothing). Now I'm getting the error Exception has already been caught error at Excp2, regardless of whether I supply 2 or 0 to throwE method.
You're looking for:
try
{ }
catch(Excp excp)
{
log(excp);
}
catch(Excp2 excp2)
{
log(excp2);
}
finally
{ }
When you catch an exception, to specify the type of the exception, and the name of of its reference.
Your original code tried to catch Exception, which is the least specific exception, so you cannot catch anything after that.
When you are catching an exception, you have to specify what type of exception you are catching, this will allow you to better handle the exception that has occured. One thing that you have to keep in mind though, is that there is that there are specific and other more "wide purpose" exceptions.
For instance, NumberFormatException is more specific than Exception, since NumberFormatException will be thrown whenever you will try to parse a string into a number.
Thus, when having multiple catch statements, always put the most specific one on top, and the more generic ones at the end. If you put the more generic ones at the beginning, they will catch the exception before it can be passed to a more specific catch statement.
In your case, you are trying to catch the same exception twice, since you have two catch statements that try to catch the same exception.
Java dispatches to the catch() clauses based on the types of the exception: your clauses are both trying to catch an exception of type Exception, and give them the names Excp and Excp2:
public class tdExc {
public static void main(String[] args) {
Exc testObj = new Exc();
try {
testObj.throwE(0);
System.out.println("This will never be printed, so sad...");
} catch(Exception Excp) {
Shouldn't this be Excp e?
System.out.println("Caught ya!");
} catch(Exception Excp2) {
Shouldn't this be Excp2 e?
System.out.println("Caught ya! Again!!!!");
} finally {
System.out.println("This will always be printed!");
}
}
}
And, while it's unrelated, I think your earlier code would be easier for you to think about if you write it more like this:
public void throwE(boolean p) throws Excp, Excp2 {
if(p) {
throw new Excp();
} else {
throw new Excp2();
}
}
Call it with true or false as parameters.
I believe the exception can only be caught once with java. The first exception handler will process the error.
Please someone tel me if this is true for java :)