How to explain whether Exception will catch RuntimeException? - java

This is very odd to me. RuntimeException inherits from Exception, which inherits from Throwable.
catch(Exception exc) { /* won't catch RuntimeException */
but
catch(Throwable exc) { /* will catch RuntimeException */
I know RuntimeException is special in that it's unchecked. But to my understanding that applies just to whether exceptions have to be declared, not whether they are caught. And even then, I don't know why this logic would break on catching Throwable.
This is pretty relevant to me since I have a situation where RuntimeException can be thrown in a terminal operation. I'm not sure the name for this pattern, but something like, my class EmailRoller takes an array of Callbacks. The code looks like this:
for(Callback cb : callbacks) {
try {
cb.call(item);
}
catch(Exception exc) {
logger.error("Error in callback: ", exc);
}
}
So this is a case where something like an OOME needs to fly through, because if one of these callbacks consumes all machine memory, that sure as heck is going to affect the running of the other ones. But a NullPointerException? Or an IndexOutOfBoundsException? Those will affect the callback but won't prevent the others from running.
Also, this is a bit of an enterprise design. Different programmers or teams can add callbacks to process the item, but they should be isolated from each other. This means, as the programmer responsible for insulating these callbacks from each other, I shouldn't rely on them to make sure errors don't slip through. Catching Exception should be about the right line, but it isn't because RuntimeException slips through. So my more general question is: what's a good pattern here? Just catch(Exception | RuntimeException exc), which I believe is a syntax error because of the inheritance?

The premise of the question is flawed, because catching Exception does catch RuntimeException. Demo code:
public class Test {
public static void main(String[] args) {
try {
throw new RuntimeException("Bang");
} catch (Exception e) {
System.out.println("I caught: " + e);
}
}
}
Output:
I caught: java.lang.RuntimeException: Bang
Your loop will have problems if:
callbacks is null
anything modifies callbacks while the loop is executing (if it were a collection rather than an array)
Perhaps that's what you're seeing?

catch (Exception ex) { ... }
WILL catch RuntimeException.
Whatever you put in catch block will be caught as well as the subclasses of it.

Catching Exception will catch a RuntimeException

I faced similar scenario. It was happening because classA's initilization was dependent on classB's initialization. When classB's static block faced runtime exception, classB was not initialized. Because of this, classB did not throw any exception and classA's initialization failed too.
class A{//this class will never be initialized because class B won't intialize
static{
try{
classB.someStaticMethod();
}catch(Exception e){
sysout("This comment will never be printed");
}
}
}
class B{//this class will never be initialized
static{
int i = 1/0;//throw run time exception
}
public static void someStaticMethod(){}
}
And yes...catching Exception will catch run time exceptions as well.

class Test extends Thread
{
public void run(){
try{
Thread.sleep(10000);
}catch(InterruptedException e){
System.out.println("test1");
throw new RuntimeException("Thread interrupted..."+e);
}
}
public static void main(String args[]){
Test t1=new Test1();
t1.start();
try{
t1.interrupt();
}catch(Exception e){
System.out.println("test2");
System.out.println("Exception handled "+e);
}
}
}
Its output doesn't contain test2 , so its not handling runtime exception.
#jon skeet, #Jan Zyka

Related

Catching an Exception and rethrowing it, but it's not an Exception

I stumbled upon code looking something like this:
void run() {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() {
throw new RuntimeException();
}
This code surprises me because it looks like the run()-method is capable of throwing an Exception, since it catches Exception and then rethrows it, but the method is not declared to throw Exception and apparently doesn't need to be. This code compiles just fine (in Java 11 at least).
My expectation would be that I would have to declare throws Exception in the run()-method.
Extra information
In a similar way, if doSomething is declared to throw IOException then only IOException needs to be declared in the run()-method, even though Exception is caught and rethrown.
void run() throws IOException {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() throws IOException {
// ... whatever code you may want ...
}
Question
Java usually likes clarity, what is the reason behind this behavior? Has it always been like this? What in the Java Language Specification allows the run() method not need to declare throws Exception in the code snippets above? (If I would add it, IntelliJ warns me that Exception is never thrown).
I have not scan through the JLS as you have asked in your question, so please take this answer with a grain of salt. I wanted to make it a comment, but it would have been too big.
I find funny at times, how javac is pretty "smart" in some cases (like in your case), but leaves a lot of other things to be handled later by JIT. In this case, it is just that the compiler "can tell" that only a RuntimeException would be caught. This is obvious, it's the only thing you throw in doSomething. If you slightly change your code to:
void run() {
try {
doSomething();
} catch (Exception ex) {
Exception ex2 = new Exception();
System.out.println("Error: " + ex);
throw ex2;
}
}
you will see a different behavior, because now javac can tell that there is a new Exception that you are throwing, un-related to the one you caught.
But things are far from ideal, you can "trick" the compiler yet again via:
void run() {
try {
doSomething();
} catch (Exception ex) {
Exception ex2 = new Exception();
ex2 = ex;
System.out.println("Error: " + ex);
throw ex2;
}
}
IMO, because of ex2 = ex; it should not fail again, but it does.
Just in case this was compiled with javac 13+33
Unchecked exceptions do not need to be declared in a method or constructor's throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary. RuntimeException is unchecked.

Will Java catch an Exception multiple times if it inherits another Exception?

given these classes:
public static class SuperException extends Exception {
}
public static class MyException extends SuperException {
}
and this happening at runtime:
try{
throw new MyException();
} catch (MyException e) {
catcher1();
} catch (SuperException e) {
catcher2();
}
which methods will be invoked? just the first? both? does it make any difference in which order I write the catch blocks?
Just the first (catcher1). The first matching catch block is executed, and none others.
With the code in the question, the second catch block is unreachable and won't compile. But if your try block contained code that may throw MyException, and also code that may throw a SuperException that isn't a MyException, and if you want to handle MyException differently from SuperException, you could have both of those blocks (and you would want them in that order).

Exception doesn't need to be thrown to be caught, but IOException does

Why does the following code compile fine, but the method being called does not need to throw Exception? Isn't Exception a checked exception and not an unchecked exception? Please clarify.
class App {
public static void main(String[] args) {
try {
amethod();
System.out.println("try ");
} catch (Exception e) {
System.out.print("catch ");
} finally {
System.out.print("finally ");
}
System.out.print("out ");
}
public static void amethod() { }
}
If I want to use a try catch with IOexception (a checked exception), the method being called needs to throw IOException. I get this.
import java.io.IOException;
class App {
public static void main(String[] args) {
try {
amethod();
System.out.println("try ");
} catch (IOException e) {
System.out.print("catch ");
} finally {
System.out.print("finally ");
}
System.out.print("out ");
}
public static void amethod() throws IOException { }
}
Isn't 'Exception' a checked exception and not an unchecked exception?
Yes, it is.
But even if we know the method doesn't throw Exception itself, the code catch(Exception e){ could still execute. The code in the try block could still throw something that inherits from Exception. That includes RuntimeException and its subclasses, which are unchecked.
catch(IOException e){, on the other hand, can only catch checked exceptions. (Java doesn't allow multiple inheritance, so anything that's a subclass of IOException can't possibly be a subclass of RuntimeException.) The compiler can fairly easily figure out that none of the code in the try block can possibly throw an IOException (since any method throwing a checked exception must explicitly say so) which allows it to flag the code.
Normally there would be a compiler error for having a try block that never throws a checked exception that you have a catch block for, but the behavior you're observing comes from the fact that the Java Language Specification treats Exception specially in this circumstance. According to ยง11.2.3:
It is a compile-time error if a catch clause can catch checked exception class E1 and it is not the case that the try block corresponding to the catch clause can throw a checked exception class that is a subclass or superclass of E1, unless E1 is Exception or a superclass of Exception.
This is reasonable because Exception (and its superclass Throwable) can be used to catch exceptions that extend RuntimeException also. Since runtime exceptions are always possible, the compiler always allows Exception to appear in a catch clause regardless of the presence of checked exceptions.

Why is catch block optional?

I have the following code
public static void nocatch()
{
try
{
throw new Exception();
}
finally
{
}
}
Which gives the error
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Unhandled exception type CustomException
My Question is why was it designed that the catch block is optional, when there is no way of getting around not having a catch?
From finally()'s perspective, I understand that
finally should have atleast a try block, catch is optional. The point of finally blocks is to make sure stuff gets cleaned up whether an exception is thrown or not. As per the JLS
A finally clause ensures that the finally block is executed after the try block and any catch block that might be executed, no matter how control leaves the try block or catch block.
Edit:
By adding a return in the finally block, compiler does not give the error WHY?!
public static void nocatch()
{
try
{
throw new Exception();
}
finally
{
return; //By adding this statement, the compiler error goes away! Please let me know why
}
}
My Question is why was it designed that the catch block is optional, when there is no way of getting around not having a catch?
Yes there is: Declare that the method throws the exception:
public static void nocatch() throws CustomException
{
try
{
throw new CustomException();
}
finally
{
}
}
try/finally without catch is to ensure that you clean up anything you need to clean up, even if you aren't handling the exception yourself. (Be sure not to allow any other exception to be thrown from within finally, or you'll hide the primary exception.)
Here's an example to play with (live copy):
private static class CustomException extends Exception {
}
public static void main (String[] args) throws java.lang.Exception
{
try
{
System.out.println("Calling nocatch(false)");
nocatch(false);
}
catch (CustomException ce) {
System.out.println("Caught CustomException for false case");
}
try
{
System.out.println("Calling nocatch(true)");
nocatch(true);
}
catch (CustomException ce) {
System.out.println("Caught CustomException for true case");
}
}
public static void nocatch(boolean foo) throws CustomException
{
try
{
if (foo) {
System.out.println("Throwing");
throw new CustomException();
}
}
finally
{
System.out.println("In finally");
}
System.out.println("Reached outside the try/finally block");
}
Output:
Calling nocatch(false)
In finally
Reached outside the try/finally block
Calling nocatch(true)
Throwing
In finally
Caught CustomException for true case
As you can see, the finally block's code runs regardless of whether an exception occurred, but the code after the try/finally doesn't.
Re your follow-up asking why adding return within the finally makes the error go away:
try
{
throw new CustomException();
}
finally
{
return; // <=== Makes the compiler happy (but don't do it!)
}
Interesting edge case! It's because the code in the finally block always runs, and so you'll always return rather than throw, hiding the exception that occurred. E.g., this is the sequence:
throw new CustomException() throws the exception, which transfers control to the finally block
Code in the finally block issues a normal return from the method
This hides the fact the exception occurred; in effect, you've "handled" the exception (without actually handling it) via the finally block. In general, this isn't a good idea; use catch to handle exceptions, or declare them on the method so calling code can handle them.

Try-Catch-Throw in the same Java class

Is it possible to catch a method in the current class the try-catch block is running on? for example:
public static void arrayOutOfBoundsException(){
System.out.println("Array out of bounds");
}
.....
public static void doingSomething(){
try
{
if(something[i] >= something_else);
}
catch (arrayOutOfBoundsException e)
{
System.out.println("Method Halted!, continuing doing the next thing");
}
}
If this is possible how will it be the correct way to call the catch method?
If this is not possible, could anyone point me in the right direction, of how to stop an exception from halting my program execution in Java without having to create any new classes in the package, or fixing the code that produces ArrayOutOfBoundsException error.
Thanks in Advance,
A Java Rookie
What you are wanting to do is handle an Exception.
public static void doingSomething(){
try {
if (something[i] >= something_else) { ... }
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Method Halted!, continuing doing the next thing");
}
}
That's all you need. No extra classes, no extra methods.
An Exception is a special type of class that can be "thrown" (you can throw it yourself by using the throw keyword, or Java may throw one for you if, for example, you try to access an array index that does not exist or try to perform some operation on a null). A thrown exception will "unwrap" your call stack ("escaping" from each function call) until your program finally terminates. Unless you catch it, which is exactly what the syntax above does.
So if you were writing a function a() that called a function b() that called a function c() and c() threw an exception, but the exception was not caught in b() or c(), you could still catch it in a():
void a() {
try {
b();
catch (SomeExceptionClass e) {
// Handle
}
}
That said, if it is possible to prevent an exception from being thrown in the first place, that is often a better idea. In your particular case, this would be possible since all arrays in Java know their own length:
public static void doingSomething(){
if (i >= something.length) {
System.out.println("Method Halted!, continuing doing the next thing");
} else {
if (something[i] >= something_else) { ... }
}
}
Hmm.. I think you are a little bit confused. You don't catch a method with try catch blocks. You catch Exceptions. Exceptions are more like things.
This alone (note the capital "A" of ArrayOutOfBoundsException) will prevent your program to terminate even if that Exception is thrown. You don't need to declare a "arrayOutOfBoundsException()" method.
public static void doingSomething(){
try
{
if(something[i] >= something_else);
}
catch (ArrayOutOfBoundsException e)
{
System.out.println("Method Halted!, continuing doing the next thing");
}
}
Note the little "e"? That's the reference you can use to refer to this Exception. So, you can ask things to this Exceptions using this little local variable. For example, if you want to print where the exception happened, you can do e.printStackTrace(); .
You catch Exceptions, with a try-catch block. Not sure if you can catch methods with this.
public static void myMethod(){
try {
// check for some given condition
}
catch (conditionNotSatisfied e) {
System.out.println("Condition was not satisfied, you tried to do something which is not allowed");
}
}
The 'e' in the catch() is the reference used for referring to an Exception.
Exception refers to this when it wishes to check your given condition and return you a warning or error about the condition not getting satisfied.
I think you mean to have the arrayOutOfBoundsException method throw the exception caused... If i understand correctly:
public static void arrayOutOfBoundsExceptionMethod() throws ArrayIndexOutOfBoundsException {
\\...
\\ code that throws the exception
}
.....
public static void doingSomething(){
try
{
if(something[i] >= something_else);
arrayOutOfBoundsExceptionMethod();
}
catch (ArrayIndexOutOfBoundsException e)
{
System.out.println("Method Halted!, continuing doing the next thing");
}
}
Is that what you are asking?
I'm trying to understand what you're asking, your terminology is wrong in places :) If you try and set an index out of bounds, you'll get a built-in exception anyway, ArrayIndexOutOfBoundsException. You can catch this and use this inside the method, or throw it using a class XX throws ArrayIndexOutOfBoundsException declaration in the header of the method, so that the invoking method can catch it (its not required to catch an ArrayIndexOutOfBoundsException as it's a RuntimeException -- i.e., nothing happens if it goes uncaught, it's unchecked.
See this wiki article for more details: http://en.wikibooks.org/wiki/Java_Programming/Throwing_and_Catching_Exceptions.
It is not clear what you mean by "Is it possible to catch a method". In your case, you should write your code as :
if(i < something.length && something[i] >= something_else);
No ArrayOutOfBoundsException is needed.

Categories