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.
Related
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.
I have some code that might throw both checked and runtime exceptions.
I'd like to catch the checked exception and wrap it with a runtime exception. But if a RuntimeException is thrown, I don't have to wrap it as it's already a runtime exception.
The solution I have has a bit overhead and isn't "neat":
try {
// some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
Any idea for a more elegant way?
I use a "blind" rethrow to pass up checked exceptions. I have used this for passing through the Streams API where I can't use lambdas which throw checked exceptions. e.g We have ThrowingXxxxx functional interfaces so the checked exception can be passed through.
This allows me to catch the checked exception in a caller naturally without needing to know a callee had to pass it through an interface which didn't allow checked exceptions.
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw rethrow(e);
}
In a calling method I can declare the checked exception again.
public void loadFile(String file) throws IOException {
// call method with rethrow
}
/**
* Cast a CheckedException as an unchecked one.
*
* #param throwable to cast
* #param <T> the type of the Throwable
* #return this method will never return a Throwable instance, it will just throw it.
* #throws T the throwable as an unchecked throwable
*/
#SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
throw (T) throwable; // rely on vacuous cast
}
There is a lot of different options for handling exceptions. We use a few of them.
https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html
Guava's Throwables.propagate() does exactly this:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw Throwables.propagate(e);
}
UPDATE: This method is now deprecated. See this page for a detailed explanation.
Not really.
If you do this a lot, you could tuck it away into a helper method.
static RuntimeException unchecked(Throwable t){
if (t instanceof RuntimeException){
return (RuntimeException) t;
} else if (t instanceof Error) { // if you don't want to wrap those
throw (Error) t;
} else {
return new RuntimeException(t);
}
}
try{
// ..
}
catch (Exception e){
throw unchecked(e);
}
I have a specially compiled .class file containing the following:
public class Thrower {
public static void Throw(java.lang.Throwable t) {
throw t;
}
}
It just works. The java compiler would normally refuse to compile this, but the bytecode verifier doesn't care at all.
The class is used similar to Peter Lawrey's answer:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
Thrower.Throw(e);
}
You can rewrite the same using instanceof operator
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;
} else {
throw new RuntimeException(e);
}
}
However, your solution looks better.
The problem is that Exception is too broad. You should know exactly what the possible checked exceptions are.
try {
// code that throws checked and unchecked exceptions
} catch (IOException | SomeOtherException ex) {
throw new RuntimeException(ex);
}
The reasons why this wouldn't work reveal deeper problems that should be addressed instead:
If a method declares that it throws Exception then it is being too broad. Knowing that "something can go wrong" with no further information is of no use to a caller. The method should be using specific exception classes in a meaningful hierarchy, or using unchecked exceptions if appropriate.
If a method throws too many different kinds of checked exception then it is too complicated. It should either be refactored into multiple simpler methods, or the exceptions should be arranged in a sensible inheritance hierarchy, depending on the situation.
Of course there can be exceptions to the rule. Declaring a method throws Exception can be perfectly reasonable if it's consumed by some kind of cross-cutting framework (such as JUnit or AspectJ or Spring) rather than comprising an API for others to use.
I generally use the same type of code structure, but condense it down to one line in one of the few times a ternary operator actually makes code better:
try {
// code that can throw
}
catch (Exception e) {
throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
}
This does not require additional methods or catch blocks which is why I like it.
lombok has this handled with a simple annotation on the method ๐
Example:
import lombok.SneakyThrows;
#SneakyThrows
void methodThatUsusallyNeedsToDeclareException() {
new FileInputStream("/doesn'tMatter");
}
In the example the method should have declared throws FileNotFoundException, but with the #SneakyThrows annotation, it doesn't.
What actually happens behind the scenes is that lombok does the same trick as the high rated answer to this same question.
Mission accomplished!
I know that the code below does make sense:
try { ... }
catch (FileNotFoundException exc) { ... }
catch (IOException exc) { ... }
But does declaring those parent and child exceptions in the throws clause make sense?
Suppose I have the following code:
public void doSomething() throws FileNotFoundException, IOException { ... }
We all know that FileNotFoundException is a subclass of IOException. Now does it make sense in any way (readability, performance, et cetera) to declare it like that, opposing to just this:
public void doSomething() throws IOException { ... }
For the Java compiler, it doesn't matter whether a subclass is in the throws clause, because the superclass exception will cover it.
However, for documentation purposes it is important. The caller of your method may want to know that it can throw a subclass exception, e.g. FileNotFoundException, and handle it differently.
try {
doSomething();
}
catch (FileNotFoundException e) {
System.out.println("File not found!");
}
catch (IOException e) {
System.out.println("An I/O error has occurred: " + e.getMessage());
}
Sometimes it makes sense to catch both exceptions, as long the the sub-class exception is specified first (otherwise, I think it won't even compile). It allows you to handle specific exceptions you care about in a different way than more general exceptions.
For example, I have code that reads from a socket. It's a blocking read, an I set a timeout, since there might be nothing to read. That's why I catch SocketTimeoutException and do nothing about it. If, on the other hand, I get other IOExceptions (IOException being an indirect super-class of SocketTimeoutException), I am throwing an exception, since a real failure happened while trying to read from the socket.
catch (SocketTimeoutException ignEx) {
// -- ignore exception, as we are expecting timeout exceptions because
// -- there might be nothing to read
}
catch (IOException ioEx) {
throw new SomeException (...);
}
As for declaring both in the method signature, It is not necessary to declare both in the throws clause, but it would be useful to the users of your method if you document both exceptions in the JavaDoc comments, and describe the conditions in which each of them are thrown.
Why can't you throw an InterruptedException in the following way:
try {
System.in.wait(5) //Just an example
} catch (InterruptedException exception) {
exception.printStackTrace();
//On this next line I am confused as to why it will not let me throw the exception
throw exception;
}
I went to http://java24hours.com, but it didn't tell me why I couldn't throw an InterruptedException.
If anyone knows why, PLEASE tell me! I'm desperate! :S
You can only throw it if the method you're writing declares that it throws InterruptedException (or a base class).
For example:
public void valid() throws InterruptedException {
try {
System.in.wait(5) //Just an example
} catch (InterruptedException exception) {
exception.printStackTrace();
throw exception;
}
}
// Note the lack of a "throws" clause.
public void invalid() {
try {
System.in.wait(5) //Just an example
} catch (InterruptedException exception) {
exception.printStackTrace();
throw exception;
}
}
You should read up on checked exceptions for more details.
(Having said this, calling wait() on System.in almost certainly isn't doing what you expect it to...)
There are two kinds of exceptions in Java: checked and unchecked exceptions.
For checked exceptions, the compiler checks if your program handles them, either by catching them or by specifying (with a throws clause) that the method in which the exception might happen, that the method might throw that kind of exception.
Exception classes that are subclasses of java.lang.RuntimeException (and RuntimeException itself) are unchecked exceptions. For those exceptions, the compiler doesn't do the check - so you are not required to catch them or to specify that you might throw them.
Class InterruptedException is a checked exception, so you must either catch it or declare that your method might throw it. You are throwing the exception from the catch block, so you must specify that your method might throw it:
public void invalid() throws InterruptedException {
// ...
Exception classes that extend java.lang.Exception (except RuntimeException and subclasses) are checked exceptions.
See Sun's Java Tutorial about exceptions for detailed information.
InterruptedException is not a RuntimeException so it must be caught or checked (with a throws clause on the method signature). You can only throw a RuntimeException and not be forced by the compiler to catch it.
i have question regarding chain exception
try{ } catch(Exception e) { throw new SomeException(); }
if i do like this
my eclipse will prompt error at line throw new SomeException();
stating "unhandled exception"
and i must put something like
try{ } catch(Exception e) {
try{ throw new SomeException(); } catch(Exception e){}
}
why must do like this
because tutorial that i read .example http://java.sys-con.com/node/36579 , does not have to do this
You'll need to declare that the method throws another exception, if the exception is a checked exception.
("The unchecked exceptions classes are the class RuntimeException and its subclasses, and the class Error and its subclasses. All other exception classes are checked exception classes." -- Java Language Specification, Second Edition, Section 11.2)
For example, rather than:
void someMethod {
try {
// Do something that raises an Exception.
} catch (Exception e) {
throw new SomeException(); // Compile error.
}
}
A throws needs to be added to the method declaration:
void someMethod throws SomeException {
try {
// Do something that raises an Exception.
} catch (Exception e) {
throw new SomeException(); // No problem.
}
}
It depends if SomeException is a checked exception or not. If it is (it extends Exception but not RuntimeException) then you have to declare it on the method or throw a RuntimeException instead.
This is what your code should look like:
...) throws SomeException {
....
try {
....
} catch (Exception e) {
throw new SomeException(e);
}
If some exception doesn't have a constructor which takes an exception, then do this:
throw (SomeException) new SomeException().initCause(e);
That way when the exception is ultimately caught, you know the root cause of the problem.
your method must declare that it may throw that exception. so, you must add:
throws SomeException {
at the end of your method's header.
You need to add "throws SomeException" to your method declaration. You need to specify any exception types that your method throws except for exceptions that descend from RuntimeException.