I have a hard time to understand why the following code compiles, while it is not a subclass of exception:
class Test
{
public void run() throws IOException
{
System.out.println("Test");
}
}
class SubTest extends Test
{
//not a subclass of IOException, still compiles
public void run() throws RuntimeException
{
System.out.println("Test from sub");
}
}
class Sub2Test extends Test
{
//not a subclass of IOException, does not compile
public void run() throws Exception
{
System.out.println("Test from sub");
}
}
I understand RuntimeException is an unchecked exception, but I thought the rule was that it must be a subclass of the parent exception?
Imagine there is a caller which calls Test#run. In the declaration of Test#run, it says it might throw IOException, so the caller knows it can catch and handle it:
Test test = // it could be instance of SubTest of Sub2Test
try {
test.run();
} catch (IOException e) {
}
Then it's ok if SubTest does not throw IOException, the caller will not miss anything.
But if you throw some checked Exception like Sub2Test, since the caller does not know it until runtime, the called is not able to catch and handle it. So it should not be compiled.
"I understand RuntimeException is an unchecked exception, but I thought the rule was that it must be a subclass of the parent exception?"
That is the general rule, as specified in the JLS in section §11.2. Compile-Time Checking of Exceptions, which states (emphasis mine)
The throws clause of an overriding method may not specify that this method will result in throwing any checked exception which the overridden method is not permitted, by its throws clause, to throw (§8.4.8.3).
But that only applies to checked exceptions, and it also explicitly states that
The unchecked exception classes (§11.1.1) are exempted from compile-time checking.
So the compiler is going to ignore the fact that RuntimeException isn't a subclass of IOException.
Related
I understand that catching a checked exception that is never thrown in the corresponding try block is invalid. Because the compiler itself would have forced the programmer to handle the exception if it was to occur.
For example, this code snippet -
try
{
}
catch(IOException e)
{
}
is invalid.
But why doesn't the compiler work the same way for the method that throws a checked exception that has never been thrown in the body of the method?
For example, this code snippet -
void test() throws IOException
{
}
is surprisingly valid.
Please explain the reason behind it. TIA.
Because you might want to allow subclasses to throw this exception.
public abstract class Parent {
public void doStuff() {}
}
public class Child {
// this is illegal, because you throw more exceptions than the overridden method
public void doStuff() throws IOException {}
}
This is even more intuitive for interfaces, the (non-default) methods of which will never throw an exception but can declare it.
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 tells you all these are valid:
try { }
catch(Exception e){}
--
try{ }
catch(NullPointerException e) {}
--
try{ }
catch(ArrayIndexOutOfBoundsException e) {}
--
try{ }
catch(RuntimeException e) {}
--
try{ }
catch(Error e) {}
--
try{ }
catch(Throwable e){ }
It's not related to a void block. It's related to an impossible path to your checked subclass of Exception.
What happens with subclasses of Exception? For example IOexception: Those are unreachable catch blocks. Nothing in the try block can lead to that exception, so the compiler just tells you: this block would never be executed, as it would never catch that subException.
The difference with throws: The concept of unreachable code doesn't exist in this context. The possibility of a method throwing an exception doesn't end in the deffinition of the method. For example:
abstract void readFile(String path) throws IOException;
This method doesn't even have a block, as it's an abstract method. It's easy to guess that this line won't ever throw any IOException. But it defines a behaviour for the extensions that will implement it. In order to override it, your method must throw the IOException.
In the same way, if someone overrides your test method:
#Override
void test() throws IOException
{
readFile(file);
}
It's not impossible to happen, in contrary to your first try-catch block.
Java follows the rule "handle or declare".
If there is a checked exception declared in your code, you must handle it (in a try/catch block) or declare it (adding 'throws' on method signature).
When you say your method may throw an exception, everyone using your method must handle or declare that exception. If you handle it, you are making your code capable of recovering. If you declare it, you are passing the problem to the caller.
The compiler is fine if you declare 'throws', he knows what to do when your method will be called.
If you declare an exception that is not actually there, you are making users of your code aware that, in a future release, you may add that exception. Users will be prepared for the day you will add that exception.
Specifying says that method can throw an exception or can not throw. But compiler don't check it, because he can't, actually. So try block only check specifying. The
point is compiler don't see deference between actual calling exception and method's specifying. If you call test() in try block, it'll valid. Sorry for my English)
I have another challenging question from javaDeathMatch game;
In the code below we are asked what kind of problem the code below has.
please correct me if I am wrong;
compilation error : None; At compile time the erasure of type parameter has not still occurred and the dynamic binding has not been taken place, so the parameter passed to the method which is of type SQLException is thought of as Exception in the method 'pleaseThrow' and it(i mean Exception not SQLException) is cast to Runtime Exception in the method with no error. The only error is that we don't have a proper catch clause to catch the exception.
public class Exption<T extends Exception> {
public static void main(String[] args) {
try {
new Exption<RuntimeException>().pleaseThrow(new SQLException());
}catch (final SQLException ex){
ex.printStackTrace();
}
}
private void pleaseThrow(final Exception t) throws T{
throw (T)t;
}
}
if we replace the catch clause with this:
catch(final RuntimeException e){
e.printStackTrace();
System.err.println("caught");
}
the exception will be caught but the System.err.println("caught") will never be printed!!! What is the problem????
This is due to type erasure. In java after compilation, every generic information is lost (there is something left, which is not relevant to this though). That means that during compilation, the generic variable T is equal to RuntimeException. So your pleaseThrow code looks like this:
private void pleaseThrow(final Exception t) throws RuntimeException{
throw (RuntimeException)t;
}
After compilation though, every generic parameter is erased to the base type. In your case, to Exception. Which leaves you with a method signature like this:
private void pleaseThrow(final Exception t) throws Exception{
throw (Exception)t;
}
Which finally is clear, why your catch block is never reached. You're trying to catch RuntimeExceptions but what you're actually throwing is a checked exception. Which then propagates upwards and is finally caught by the JVM.
Additional reading: Oracle Tutorial on type erasure
This code will fail to compile, because SQLException is a checked exception, and to catch a checked exception, it must be declared to be thrown by something inside of the try block. Here it is failing to compile on Ideone, for example, with the following message:
Main.java:7: error: exception SQLException is never thrown in body of corresponding try statement
}catch (final SQLException ex){
^
Note: Main.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
If you change the catch block so it catches RuntimeException, then the code will compile, but the exception will not be caught, because SQLException is not a subclass of RuntimeException.
There's a discussion of how the pleaseThrow method works here. That idiom is usually called "sneaky throws", and it lets the caller throw a checked exception as if it was an unchecked exception. For the difference between checked and unchecked exceptions, see the official tutorial or this Q&A and StackOverflow.
Let us take the first version of your code :
public class Exption<T extends Exception> {
public static void main(String[] args) {
try {
new Exption<RuntimeException>().pleaseThrow(new SQLException());
}catch (final SQLException ex){ // This is compilation error
ex.printStackTrace();
}
}
private void pleaseThrow(final Exception t) throws T{
throw (T)t;
}
}
How is compiler able to detect the error ?
It is not because of throw (T)t;. Infact , if you type cast to a type parameter , compiler ignores it and leaves it to JVM.
Then how does compiler able to generate error ?
It is because of this :
private void pleaseThrow(final Exception t) throws T
Notice the throws T . When you say new Exption<RuntimeException>() , compiler does not create any object. But it infers T during compilation. It comes under it powers.
Now , let us understand the whole picture of why error gets generated.
Compiler from private void pleaseThrow(final Exception t) throws T{ knows that you will throw RuntimeException.
According to rule of type casting , compiler checks both types if one is parent of other. If yes , it passes the code to JVM . Only JVM will then further check if one object can actually be type casted to other.
Similarly, compiler checks for throws and catch block if any is compatible or not. If more than one is compatible, it leaves the decision to JVM. Compiler checks for many other things too but let us focus on the main track.
In your example, One type is SqlException and other is RuntimeException. None is parent of other. Hence, compiler shows error.
Let us see few examples to clear it :
public class Exption<T extends Exception> {
public static void main(String[] args) {
try {
new Exption<RuntimeException>().pleaseThrow(new IllegalArgumentException());
}catch (final ClassCastException ex){
ex.printStackTrace();
System.out.println("done");
}
}
private void pleaseThrow(final Exception t) throws T{
throw (T)t;
}
}
In this example, Catch clause won't be called , however code compiles fine.
Since ClassCastException is a RuntimeException , Compiler compiles the code fine. RuntimeException is parent to ClassCastException.
But when compiler hands over code to JVM, JVM knows that exception object is of type IllegalArgumentException and hence will settle for a catch clause of IllegalArgumentException or it's super type. Here we have nothing like that. Hence, Catch clause won't be called as there is no match.
Take another example :
public class Exption<T extends Exception> {
public static void main(String[] args) {
try {
new Exption<RuntimeException>().pleaseThrow(new IllegalArgumentException());
}catch (final RuntimeException ex){
ex.printStackTrace();
System.out.println("done");
}
}
private void pleaseThrow(final Exception t) throws T{
throw (T)t;
}
}
This runs fine and catch block is called. JVM knows object type will be IllegalArgumentException and RuntimeException is super class , hence , it matches due to super class able to refer child class object.
Now, let us come back to your code.
You have only written only one catch block consisting of SqlException which is a checked exception and hence cannot be thrown from pleaseThrow() as it throws RuntimeException according to compiler.
So, this error gets generated :
Error:(9, 10) java: exception java.sql.SQLException is never thrown in body of corresponding try statement
As you know it is illegal in Java to have a catch block catching a checked expression never thrown.
Now , let us come to version 2 of your code :
public class Exption<T extends Exception> {
public static void main(String[] args) {
try {
new Exption<RuntimeException>().pleaseThrow(new SQLException());
}catch(final RuntimeException e){
e.printStackTrace();
System.err.println("caught");
}
}
private void pleaseThrow(final Exception t) throws T{
throw (T)t;
}
}
Now, things make sense as in catch block you have written RuntimeException.
Compiler sees that method throws RuntimeException and in catch block too we have runtime exception.
Now, let us look more closely. Compiler easily compiles this code and send it to JVM. But before that it does the type erasure.
Let us look what would type erasure would have done to our code :
[In actual code given to JVM is byte level code. The below example is to show what type erasure does to the code. Note that below code won't run properly in compiler if you try to compile as this code is after type erasure and few details have been lost which compiler needs. JVM however can run the equivalent byte code of this.]
public class Exption {
public static void main(String[] args) {
try {
new Exption().pleaseThrow(new SQLException());
}catch(final RuntimeException e){
e.printStackTrace();
System.err.println("caught");
}
}
private void pleaseThrow(final Exception t) throws java.lang.Exception {
throw (java.lang.Exception) t;
}
}
To understand how this code was reduced to , you need to read about type erasure. But trust me till here for time being.
Now, this code is very interesting piece of code.
On this code JVM directly operates. If you see JVM knows it method throws an Object of type SqlException type casted to Exception. It tries to find a match in catch blocks but no match. RunTimeException is not a super class of SqlException. Hence, no catch block is called.
Let us modify the code to understand it more.
public class Exption<T extends Exception> {
public static void main(String[] args) {
try {
new Exption<RuntimeException>().pleaseThrow(new SQLException());
}catch(final RuntimeException e){
e.printStackTrace();
System.err.println("caught");
}catch(Exception r){
System.out.println("done");
}
}
private void pleaseThrow(final Exception t) throws T{
throw (T)t;
}
}
This will output "done".
I'm using Netbeans 8 IDE and I just came to this odd situation. Let's say I've a method in a class that throws and Exception and when I call that method Netbeans does not enforce the try catch. Sometimes an Exception may occur and it is not catch.
Why isn't Netbeans enforcing the try catch method?
Here's an example:
public class MyMethodClass {
public MyMethodClass() {}
public void someMethod() throws NullPointerException {
// do something
if(something == null) {
throw new NullPointerException();
}
// do something else
}
}
public class MyClass {
public MyClass() {
MyMethodClass mmc = new MyMethodClass();
// Here Netbeans does not force me to use a try catch, why?
mmc.someMethod();
}
}
NullPointerException is an unchecked exception, which means that you don't always need to catch it. Unchecked exceptions are those which extend RuntimeException or Error. The main purpose of these is for cases where there usually is no recovery; methods aren't required to declare unchecked exceptions either. This is perfectly valid:
public void throwNPE() {
throw new NullPointerException();
}
Here is one of Oracle's statements on checked vs unchecked exceptions.
NullPointerException is an unchecked exception (since it's a subclass of RuntimeException). You don't have to catch unchecked exceptions for the code to compile.
RuntimeException and its subclasses are unchecked exceptions. 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
Because NullPointerException is an unchecked exception.
I know that each java class should extend the Throwable class so that exceptions can be handled. Is this done by:
public class Test extends Throwable
or
public class Test throws Throwable?
Primitive types, or object whose class doesn’t extend Throwable cannot be thrown as exceptions.
Interpretation:
throw 3;
doesn't work because 3 is a primitive type.
throw new String();
doesn't work because String doesn't extend Throwable.
throw new RuntimeException();
works because RuntimeException is a subclass of Throwable.
I know that each java class should extend the Throwable class so that exceptions can be handled.
No, someone lied to you.
To handle exceptions, you need to keep in mind two things:
If it's a checked exception, then the class will refuse to compile if there is not a try...catch block wrapping the dodgy code, or if you don't declare the exception to be thrown.
try {
File f = new File("Foo.txt");
} catch (FileNotFoundException f) {
System.out.println("File doesn't exist!");
}
or:
public void doDodgyStuffWithFile throws FileNotFoundException { }
If it is an unchecked exception, then you will not get a compile-time failure for not catching the dodgy code, but you may get runtime exceptions from it.
String input = scanner.nextLine();
System.out.println(Integer.parseInt(input));
If you are throwing or catching the exception, be as specific as possible. Do not give into the temptation to throw/catch Exception, and never catch a Throwable.
When a class extends a Throwable, the class is a sub-class of Throwable and you can throw this class as a Throwable anywhere in you code.
class MyCoolThrowable extends Throwable{
try {
//... some error ...
} catch (MyCoolThroable t) {
//... handle the throwable
}
}
You add throws Throwable to a constructor or method so that the code that calls your constructor/method will be forced to use try-catch
void mySweetMethod() throws Throwable {
//...
}
try {
mySweetMethod();
} catch(Throwable t) {
//... handle it here
}
I think this clarified what you have read:)
I have some few doubts on exceptions.
Can anyone tell me why java doesnt allow us to create Checked Exception in a Subclass while it allows Unchecked exception in a subclass
Below exampple throws Compile time error when I use 'throws IOException' , BUT it doesnt throw any error when I use 'throws ArithmeticException' in a subclass.. I just wanna know the actual reason behind it, so can you please?
Here is code (you will get compile time error)
package com.exception.test;
import java.io.IOException;
public class Parent {
void msg() {
System.out.println("Parent...");
}
public static void main(String[] args) {
Parent parent = new Child();
parent.msg();
}
}
class Child extends Parent {
void msg() throws IOException {
System.out.println("Child...");
}
}
//using unCheckedException
package com.exception.test;
import java.io.IOException;
public class Parent {
void msg() {
System.out.println("Parent...");
}
public static void main(String[] args) {
Parent parent = new Child();
parent.msg();
}
}
class Child extends Parent {
void msg() throws ArithmeticException {
System.out.println("Child...");
}
}
If a subclass method declares it can throw a checked exception that the parent doesn't, it breaks the Liskov substitution principle, which is one of the corner stones of object oriented programming.
Consider this bit of code, with Child.msg declared to throw a checked exception:
void doMsg(Parent p) {
p.msg();
}
The program semantics break if you pass in a child object because the checked exception is now neither being caught nor thrown: the exception is no longer "checked."
Since unchecked exceptions can be thrown everywhere, declaring to throw one serves no other purpose than documentation. Therefore it can be allowed safely.
The msg() method in your parent class can throw any unchecked exception it likes. Hence, if you explicitly declare that your child throws an unchecked exception, you're not actually altering the contract. Your child method may throw an ArithmeticException, but so might your parent method.
Checked exception can be narrowed down while overriding, but not can't be broaden. Unchecked exception need not be caught by the overridden methods
From the java specs
The checked exception classes named in the throws clause are part of
the contract between the implementor and user of the method or
constructor. The throws clause of an overriding method may not specify
that this method will result in throwing any checked exception which
the overridden method is not permitted, by its throws clause, to
throw.
Unfortunately, you have hit yet another pitfall of Java's misfeature known as Checked Exceptions. The error you are receiving is an actual problem that all Java professionals face: you are implementing a method with some code that happens to throw a checked exception not declared by the superclass method. The declared checked exceptions are a part of the Java method signature; you can reduce the list in a subclass, but you cannot expand it.
If this is more that just a "why" question, and you need a workaround, the standard idiom is
try {
...code that throws the checked exception...
} catch (TheCheckedException e) { throw new RuntimeException(e); }
This is called exception wrapping. If you have more than one or two undeclared checked exceptions, you can also use the opposite idiom, ensuring that all declared exceptions propagate transparently and all undeclared ones get wrapped:
try {
...code that throws various checked exceptions...
}
catch (DeclaredEx1 | DeclaredEx2 | RuntimeException e) { throw e;}
catch (Exception e) { throw new RuntimeException(e); }