Java allows me to compile the following code without any issues:
public class Test {
public static void main(String[] args){
try {
throw new RuntimeException();
} catch (Exception e) {
throw e;
}
}
}
Even though java.lang.Exception is a checked exception. Meaning that I am rethrowing unchecked exception as checked and get away with that.
Most likely Java compiler is able to figure out that no checked exception is thrown in the try block, but I can't find the section in the specification that backups that.
Can one rely on this behavior and starting from which JDK version?
Update:
This class doesn't compile with Java 1.6.0_38 with the following message:
Test.java:6: unreported exception java.lang.Exception; must be caught or declared to be thrown
throw e;
^
1 error
It looks like that this is one of the effects of the enhancement in Java 7: Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking. See section "Rethrowing Exceptions with More Inclusive Type Checking."
The Java SE 7 compiler can determine that the exception thrown by the statement throw e must have come from the try block, and the only exceptions thrown by the try block can be FirstException and SecondException. Even though the exception parameter of the catch clause, e, is type Exception, the compiler can determine that it is an instance of either FirstException or SecondException.
Please note, that the following will not compile though even in Java 7 and above:
public class Test {
public static void main(String[] args){
try {
throw new RuntimeException();
} catch (Exception e) {
Exception e1 = e;
throw e1;
}
}
}
Because:
This analysis is disabled if the catch parameter is assigned to another value in the catch block.
The part of the Java Language Specification that governs this can be found in JLS 11.2.2
11.2.2. Exception Analysis of Statements
...
A throw statement whose thrown expression is a final or effectively
final exception parameter of a catch clause C can throw an exception
class E iff:
E is an exception class that the try block of the try statement which declares C can throw; and
E is assignment compatible with any of C's catchable exception classes; and
E is not assignment compatible with any of the catchable exception classes of the catch clauses declared to the left of C in the same try
statement.
When E is RuntimeException 1) E can be thrown in the try block, 2) the catch clause can catch it, and 3) there are no catch clauses "to the left". Therefore the throw in the catch clause can throw RuntimeException.
On the other hand, E is Exception, E cannot be thrown in the try block. Therefore the throw in the catch clause cannot throw Exception.
Related
Why does the following code not execute,
try {
System.out.println("abc");
}
catch(FileNotFoundException e) {
e.getMessage();
}
but why does this execute
try {
System.out.println("abc");
}
catch(Exception e) {
e.getMessage();
}
A print statement will not throw a FileNotFoundException error whereas Exception will catch any generic exception in Java.
That is because FileNotFoundException is a so-called Checked Exception.
It can only occur if System.out.println explicitly throws it.
The Compiler can detect that & will flag it.
On the other hand, Exception could be masking a RuntimeException or Subclass thereof.
(for example NullPointerException, which need not be explicitly declared)
The Compiler cannot detect that, and therefore must allow subclasses of RuntimeException, RuntimeException itself, Exception and Throwable.
Java docs explains clearly about object coherency while dealing with type-casting,return type of Over-riding method and throwing and catching Exceptions. But now i am little confused with Exceptions, What is the hidden concept behind this code..
void getNames() throws SQLClientInfoException { /*throws Subclass object to caller*/
try{
// throwing Subclass object to catch block but up-casting to Exception
throw new SQLClientInfoException();
} catch (Exception e) {
throw e; /* re-throwing throwing as Exception
}
}
Its a feature of programming language introduced in Java SE 7 - Use more precise re-throw in exceptions.
The Java SE 7 compiler performs more precise analysis of re-thrown exceptions than earlier releases of Java. This enables to specify more specific exception types in the throws clause of a method declaration.
Prior to Java 7:
void aMethod() throws CustomDbException {
try {
// code that throws SQLException
}
catch(SQLException ex) {
throw new CustomDbException();
}
}
Re-throwing an exception in the catch block need not indicate the
actual exceptions possible from the try block.
The type of exception thrown could not be changed without changing
the method signature.
In Java 7 or higher:
void aMethod() throws IOException {
try {
Files.copy(srcePath, trgtPath); // throws IOException
}
catch(Exception ex) {
throw ex;
}
}
The above code is legal in Java 7.
If an exception of some type is thrown in the try clause and is not assigned an exception variable in the catch clause, the compiler will copy over the checked exception type that can be thrown from the try block. (It is as if throwing all the exceptions possible from the try block provided that the exception variable is not reassigned).
The compiler knows that the only possible exception type is an IOException (because that is what the Files.copy() can throw).
Also, see this article at Oracle's website: Rethrowing Exceptions with More Inclusive Type Checking.
Because SQLClientInfoException is a subclass of "java.lang.Exception", it is caught by catch block when SQLClientInfoException is thrown
"e" variable in the catch block refers to SQLClientInfoException.
This question already has answers here:
Why is throwing a checked exception type allowed in this case?
(3 answers)
Closed 6 years ago.
Consider the following code:
static void main(String[] args) {
try {
} catch (Exception e) {
throw e;
}
}
This code compiles without having to add throws Exception to the method signature. (It behaves similarly with Throwable in place of Exception, too).
I understand why it can be run safely, in that Exception can't actually be thrown in the try block, so a checked exception cannot be thrown; I'm interested to know where this behaviour is specified.
It's not simply that the throw e is never reached: the following code also compiles:
static void stillCompilesWithThrownUncheckedException() {
try {
throw new NullPointerException();
} catch (Exception e) {
throw e;
}
}
But if you throw a checked exception, it doesn't compile, as I expect:
static void doesNotCompileWithThrownCheckedException() {
try {
throw new Exception();
} catch (Exception e) {
throw e; // error: unreported exception Exception; must be caught or declared to be thrown
}
}
In JLS Sec 11.2.2, it says:
A throw statement (§14.18) whose thrown expression has static type E and is not a final or effectively final exception parameter can throw E or any exception class that the thrown expression can throw.
My interpretation of this statement is that throw e can throw Exception, because the static type of e is Exception. And then, in JLS Sec 11.2.3:
It is a compile-time error if a method or constructor body can throw some exception class E when E is a checked exception class and E is not a subclass of some class declared in the throws clause of the method or constructor.
But it's not a compile-time error in the first two cases. Where is this behavior described in the language spec?
Edit: having marked it a dupe, I was going to ask the follow-up question: why isn't throw e; considered unreachable in the first example.
The answer was much easier to find in JLS Sec 14.21:
A catch block C is reachable iff both of the following are true:
Either the type of C's parameter is an unchecked exception type or Exception or a superclass of Exception, or some expression or throw statement in the try block is reachable and can throw a checked exception whose type is assignable to the type of C's parameter. (An expression is reachable iff the innermost statement containing it is reachable.)
See §15.6 for normal and abrupt completion of expressions.
There is no earlier catch block A in the try statement such that the type of C's parameter is the same as or a subclass of the type of A's parameter.
Both of these are true (it's of type Exception, and there's no earlier catch block), so it's "reachable". I guess the effort of calling out an empty try block as a special case was too great for such a marginally-useful construct.
I believe the very next paragraph of section 11.2.2 answers the question:
A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:
E is an exception class that the try block of the try statement which declares C can throw; and
…
So, throw e; “can throw” only exceptions which the corresponding try-block “can throw,” where the latter is defined by the actual statements in the try-block.
Obviously an empty try-block does not qualify as a “can throw” section for any exception class. Your second example “can throw” NullPointerException, and since the catch-block “can throw” only the exception that the try-block “can throw,” the catch-block too can throw only the unchecked NullPointerException.
Your third example’s try-block “can throw” java.lang.Exception itself, therefore the catch-block “can throw” java.lang.Exception, so java.lang.Exception must be caught or declared to be thrown.
I am confused about the behaviour of the CustomExceptions in below program.If Line2 is commented and Line1 is not then program works well,but if Line1 is commented and Line2 is not then compile time error comes as "Unreachable catch block for CustomChecked.This exception is never thrown from the try statement body" for Line3.Please help me why this comple time exception comes only for the unChecked Exception?.
try
{
if(true)
{
throw new CustomChecked("Checked Exception");// Line1
// throw new CustomUnChecked("Un-Checked Exception");// Line2
}
}
catch(CustomChecked ex) //Line3
{
System.out.println(ex.getMessage());
}
catch(CustomUnChecked ex)
{
System.out.println(ex.getMessage());
}
Exceptions :
class CustomChecked extends Exception
{
public CustomChecked(String msg) {
super(msg);
}
}
class CustomUnChecked extends RuntimeException
{
public CustomUnChecked(String msg) {
super(msg);
}
}
CustomUnChecked is a RuntimeException which is unchecked meaning that the complier doesn't check who can/do throw that exception. Compiler assumes that every object/method/code block can throw any type of RuntimeException and so that you can always check for this type of exceptions in your check statements.
On the other hand CustomChecked is checked, meaning that the compiler checks for all methods and code blocks that can throw it. So you can only catch the checked exception if you know (at a complie time) that you invoke a method/code that throws the exception inside the try block.
So to sum up - your compilator informs you, that the catch you have in line 3 is not needed (and so should be removed), because there is no way that somebody will throw CustomCheckedException inside the try statement. As CustomUnCheckedException is not checked by compiler (it is runtime, assumed to be thrown unexpected anywere), the check statement for it can stay.
The part of the Java Spec that is applicable here is 11.2.3. It reads
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.
Notice that this clause is restricted to 'checked' exceptions. Unchecked exceptions, by definition of being 'unchecked' do not have these checks applied to them. Hence the difference in behavior that you are seeing.
The compiler does not check if you catch RuntimeExceptions, but it does check that you catch Exceptions. Thats why you get an error if you try to catch a non-existant checked exception (if its not in the throws clause, it shouldnt exist, since its a checked exception), and no error if you are catching a RuntimeException (which can happen even through you didnt put it in the throws clause, a NullPointerException for example).
So, in short, CheckedExceptions MUST be declared in the throws clause and MUST be catched.
Unchecked exceptions CAN be catched, but the compiler has no way of knowing the if code throws an unchecked exception, so it wont give you an error if you check on it or not.
I noticed by accident that this throw statement (extracted from some more complex code) compiles:
void foo() {
try {
} catch (Throwable t) {
throw t;
}
}
For a brief but happy moment I thought that checked exceptions had finally decided to just die already, but it still gets uppity at this:
void foo() {
try {
} catch (Throwable t) {
Throwable t1 = t;
throw t1;
}
}
The try block doesn't have to be empty; it seems it can have code so long as that code doesn't throw a checked exception. That seems reasonable, but my question is, what rule in the language specification describes this behavior? As far as I can see, §14.18 The throw Statement explicitly forbids it, because the type of the t expression is a checked exception, and it's not caught or declared to be thrown. (?)
This is because of a change that was included in Project Coin, introduced in Java 7, to allow for general exception handling with rethrowing of the original exception. Here is an example that works in Java 7 but not Java 6:
public static demoRethrow() throws IOException {
try {
throw new IOException("Error");
}
catch(Exception exception) {
/*
* Do some handling and then rethrow.
*/
throw exception;
}
}
You can read the entire article explaining the changes here.
I think that the wording in §14.18 The throw Statement, that you refer to, is a mistake in the JLS — text that should have been updated with Java SE 7, and was not.
The bit of JLS text that describes the intended behavior is in §11.2.2 Exception Analysis of Statements:
A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:
E is an exception class that the try block of the try statement which declares C can throw; and
E is assignment compatible with any of C's catchable exception classes; and
E is not assignment compatible with any of the catchable exception classes of the catch clauses declared to the left of C in the same try statement.
The first bullet point is the relevant one; because the catch-clause parameter t is effectively final (meaning that it's never assigned to or incremented or decremented; see §4.12.4 final Variables), throw t can only throw something that the try block could throw.
But as you say, the compile-time checking in §14.18 does not make any allowance for this. §11.2.2 does not decide what's allowed and what's not; rather, it's supposed to be an analysis of the consequences of the various restrictions on what can be thrown. (This analysis does feed back into more-normative parts of the spec — §14.18 itself uses it in its second bullet point — but §14.18 can't just say "it's a compile-time error if it throws an exception it can't throw per §11.2.2", because that would be circular.)
So I think §14.18 needs to be adjusted to accommodate the intent of §11.2.2.
Good find!
This behavior is described in detail in the JLS in 11.2. Compile-Time Checking of Exceptions:
A throw statement whose thrown expression is a final or effectively
final exception parameter of a catch clause C can throw an exception
class E iff:
E is an exception class that the try block of the try statement which
declares C can throw; and
E is assignment compatible with any of C's catchable exception
classes; and
E is not assignment compatible with any of the catchable exception
classes of the catch clauses declared to the left of C in the same try
statement.
(Emphasis mine.)
Your second example fails because t1 is not an "exception parameter of a catch clause".