throwing Generic Exception in java - java

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".

Related

Declaring checked exception using throws clause that is never thrown in the body of the method

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)

Thrown checked exception without throws declaration in method

The following code compiles and runs on Java 13:
public class CheckedExceptionSSCE {
public static void main(String[] args) {
try {
methodNoThrowsDeclaration();
} catch (Exception e) {
// why is this throw allowed?
// no throws in main()
throw e;
}
}
private static void methodNoThrowsDeclaration() {
System.out.println("doesn't throw");
}
}
How come the throw e is allowed?
Is it specified somewhere in the JLS? I was not able to find it, perhaps I'm using wrong keywords to search.
Is the compiler smart enough to deduce that there will be no real checked exception thrown and thus allows the code to compile and run?
This is a feature that was added in Java 7.
The compiler can derive the type of exception if you use a variable from the catch clause to rethrow the exception. Since you have no checked exception to be caught, it knows that e could only be RuntimeException and no throws definition is needed.
More information:
https://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html
The method:
private static void methodNoThrowsDeclaration() {
System.out.println("doesn't throw");
}
does not throw any checked exception, from this SO thread one can read:
You can throw unchecked exceptions without having to declare them if
you really want to. Unchecked exceptions extend RuntimeException.
therefore there is no need to adapt the main method signature.
From the Java language specification (§14.18 The throw Statement) one can read:
ThrowStatement: throw Expression ;
At least one of the following three conditions must be true, or a
compile-time error occurs:
The type of the Expression is an unchecked exception class (§11.1.1)
or the null type (§4.1).
The throw statement is contained in the try block of a try statement
(§14.20) and it is not the case that the try statement can throw an
exception of the type of the Expression. (In this case we say the
thrown value is caught by the try statement.)
The throw statement is contained in a method or constructor
declaration and the type of the Expression is assignable (§5.2) to at
least one type listed in the throws clause (§8.4.6, §8.8.5) of the
declaration.
The code that you have shown follows at least the first condition. However, let us look at the following example, where non of those three aforementioned conditions are true, namely if you do :
private static void methodNoThrowsDeclaration() {
System.out.println("doesn't throw");
throw new Exception();
}
that would force you to do:
private static void methodNoThrowsDeclaration() throws Exception {
System.out.println("doesn't throw");
throw new Exception();
}
which in turn would give a compiler error:
Unhandled exception: java.lang.Exception
at the statement throw e;.

Why must I catch exceptions when providing lambda argument?

Consider the following example:
public class LambdaArgsTest {
private static void display(Supplier<?> arg) {
try {
// this is the place where the Exception("wrong") might be thrown
// and it is in fact handled
System.out.println(arg.get());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
display(() -> {
if(/*some condition*/) {
// this statement will be rejected due to unhandled exception
throw new Exception("wrong");
}
return "abcde";
});
}
}
Here comes the question: the lambda argument in the above example is an object that'll be executed later inside the "display()" method. It is obviously not executed when passing the arguments to the "display()".
Why is it rejected by the compiler? I think it's quite reasonable to surround it by try...catch only when the lambda is actually called.
This is because of the signature of Supplier functional interface:
T get();
As you see, the method get is not declared to throw Exception (neither any other checked exception).
In Java, there are checked vs unchecked exceptions (unchecked exceptions are those which inherit from RuntimeException). Checked exceptions must be handled, either by catching them in a catch block, or by declaring that the method throws that exception.
If the signature of Supplier.get were:
T get() throws Exception:
The code would compile fine.
Try throwing RuntimeException instead of Exception and the code will compile fine.
EDIT: As per Peter Lawrey's suggestion in the comments, if you do need to throw a checked exception from within your lambda expression, you could use e.g. Callable, whose only one method's signature is as follows:
T call() throws Exception;
You'd just need to pass a Callable to your display method instead of a Supplier.

Why does this compile? Overriding method not a subclass of exception

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.

does the compiler consider actual types in error handling in java

why does this work
class blah{
public void someMethod(){
try{
throw new NullPointerException();
}
catch(Throwable t){
System.out.println("Caught!");
throw t;
}
}
}
it seems like the compiler some how see the actual type of t
It works because NullPointerException is an instance of Throwable. The catch clause catches all instances of the declared type.
That code will fail to compile before Java 7.
From the Java SE 7 Features and Enhancements, section Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking:
Rethrowing Exceptions with More Inclusive Type Checking
The Java SE 7 compiler performs more precise analysis of rethrown exceptions than earlier releases of Java SE. This enables you to specify more specific exception types in the throws clause of a method declaration.
Consider the following example:
static class FirstException extends Exception { }
static class SecondException extends Exception { }
public void rethrowException(String exceptionName) throws Exception {
try {
if (exceptionName.equals("First")) {
throw new FirstException();
} else {
throw new SecondException();
}
} catch (Exception e) {
throw e;
}
}
This examples's try block could throw either FirstException or SecondException. Suppose you want to specify these exception types in the throws clause of the rethrowException method declaration. In releases prior to Java SE 7, you cannot do so. Because the exception parameter of the catch clause, e, is type Exception, and the catch block rethrows the exception parameter e, you can only specify the exception type Exception in the throws clause of the rethrowException method declaration.
However, in Java SE 7, you can specify the exception types FirstException and SecondException in the throws clause in the rethrowException method declaration. 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:
public void rethrowException(String exceptionName)
throws FirstException, SecondException {
try {
// ...
}
catch (Exception e) {
throw e;
}
}
NullPointerException is a child of Excepsion. Exception is a child of Throwable. So thats should work becouse of Polymorphism.

Categories