Why we don't have to add try-catch to a RuntimeException?
I want to ask why we don't have to add try-catch block to a RuntimeException
while we should do that with other exceptions?
I mean like :
public class Main {
public static void main(String[] args) {
throw new RuntimeException();
}
}
Edit :
when I say : throw new RuntimeException();
it is so clear that there is an exception will happen ,so why the compiler doesn't forbid that ?
That's because it's an unchecked exception. It doesn't need to be explicitly declared or catched. Also see the Java tutorial on the subject.
In general, you should only throw a RuntimeException
(preferably one of its "Direct Known Subclasses" listed in the javadoc) to signal that the caller is doing it wrong. E.g. when the caller incorrectly passes a null
argument (then throw NullPointerException
), or an illegal argument (then throw IllegalArgumentException
), or when the caller invokes the method at the wrong moment/state (then throw IllegalStateException
), etcetera. The caller is supposed to fix their code to avoid that. E.g. checking beforehand if the argument is not null, or if the argument is in correct format/syntax, or ensuring that the method is called at the right moment.
If there is a specific situation which should throw a runtime exception and you can't use one of its specific subclasses, then you are supposed to extend it and document it properly in the new exception's javadoc and in the calling method, e.g. ConfigurationException extends RuntimeException
for the case that the calling code hasn't configured the application/API properly before use. This should signal the enduser (the other developer) sufficiently to take action accordingly.
In a nutshell:
-
RuntimeExceptions
should identify programmatically recoverable problems which are caused by faults in code flow or configuration under control of code developer (read: developer's faults). - Checked
Exceptions
should identify programmatically recoverable problems which are caused by unexpected conditions outside control of code developer (e.g. database down, file I/O error, wrong enduser input, etc). -
Errors
should identify programmatically unrecoverable problems outside control of code developer (e.g. out of memory, exception inside an initializer, etc).
Lets argue this way. What if NullPointerException was designed to be a compile time exception? Had it been done so, the compiler had to strictly check whether a variable is null or not. There is no way that this can be done.
public void dummyMethod(Object obj){
}
Here there is no way for the compiler to check whether the obj can be null or not. However, there has to be some error/exception has to be thrown when you have a null pointer scenario.
RuntimeException
, Error
and their subclasses are specifically not compile-time checked - they are not part of the formal contract of the method.
See Chapter 11 in the JLS, Exceptions, in particular 11.2, Compile-time checking of Exceptions.
- JLS, Ch. 11, Exceptions.
Per language specification, unchecked exceptions are not checked at compile-time which means that the compiler does not require methods to catch or to specify (with a throws
) them. Classes belonging to this category are detailed in the section 11.2 Compile-Time Checking of Exceptions of the JLS:
The unchecked exceptions classes are the class
RuntimeException
and its subclasses, and the classError
and its subclasses. All other exception classes are checked exception classes. The Java API defines a number of exception classes, both checked and unchecked. Additional exception classes, both checked and unchecked, may be declared by programmers. See §11.5 for a description of the exception class hierarchy and some of the exception classes defined by the Java API and Java virtual machine.
So because a RuntimeException
in a unchecked exception, the compiler doesn't force you to handle it. If you want to force the caller of a piece of code to handle an exception, use a checked exception (the subclasses of Exception
other than RuntimeException
are all checked exception classes).
Most of the answers on this forum have been talking about the Exception hierarchy and the Java compiler not catching them but I would try to answer this more from the design perspective and why perhaps things were designed like this.
Basically when you call a function(or write some code) an exception can be thrown out of it based on three different situations:
Based on an unavoidable condition like unavailability of network or some expected file missing on the file system.
Based on an avoidable but known condition like
Integer.parseInt(String)
can throwNumberFormatException
if the caller passes a unconvertible string like"Hello"
, but the caller may ensure proper validations in place before passing in any string to the function and completely do away with the possibility of generating the exception. A common use case could be validating the form fieldage
on a web page before passing it to deeper layers that make the conversion.An unknown or unexpected condition Any time some line of code can throw an exception in your code because there was some mistake that you did and didn't observe the error condition until it blasted off in production, generally happens with
NullPointer Reference
,IndexOutOfBounds
etc, which if observed would possibly fall in category 2.
Exceptions of category 1 are generally designed as Checked Exceptions
because it needs to enforce the check for unavoidable error conditions, and to enforce their fallbacks. For examples IOException is checked exception, because in case you are opening a file, there can be a lot many things that may go wrong(like file may be deleted, permissions etc.)and pre validating all of them can be very cumbersome.
Exceptions of the 2nd type are generally modeled as Unchecked Exceptions
because you might have your pre validation in place and it might be irritating to be forced to use try and catch for situations that you have already have taken care of.
Exceptions of the 3rd type need not be even worried about generally because you cannot put error handling in each and every statement of application code that can unexpectedly come up. But sometimes you can place a global handler, somewhere quite up in the call stack from where almost all the application code gets executed and handle it in a generic manner so that your application does not crash due to an unexpected error.
For example, if you're running a web application you can configure your Servlet Container to send out a generic 500 Internal Server Error
for any unhandled error in your application. Or, if you're running a standalone Java application you can keep the contents of your main method
in a try catch
block to prevent crashing the application.