mscharhag, Programming and Stuff;

A blog about programming and software development topics, mostly focused on Java technologies including Java EE, Spring and Grails.

Wednesday, 4 September, 2013

Java Exceptions and generic types

In this post I want to talk a bit about Java exception in combination with generic type parameters.The post is divided in two sections. The first one is about generic exceptions, the second one is about passing and throwing exceptions as generic type parameters.

Generic classes are not allowed to subclass Throwable

Let's look at the following code

public class MyException<T> extends RuntimeException { // won't compile

}

This code won't compile because subclasses of Throwable cannot have a generic type parameter. RuntimeException subclasses Exception which again is a subclass of Throwable. So the compiler rejects this code.

If you think a bit about this it makes sense. I cannot think of a useful way of catching generic exception.

Let's assume for the moment the exception definition from above would be valid Java code. How would you throw and catch this exception?

public void catchIt() {
  try {
    throwIt();
  } catch (MyException<String> e) {
    ..
  } catch (MyException<Integer> e) {
    ..
  } catch (MyException<?> e) {
    ..
  }
}

In order to make the generic type on the exception class useful it should be possible to create different catch blocks for different generic types. This however, is not possible because of type erasure. At runtime all the generic type information will be lost and MyException<String> will just be MyException. So there is no way for the Java runtime to decide which catch block should be executed.

Additionally it would not be possible to generalize the type parameter in the catch block because Generics in Java are invariant. This means that MyException<Integer> cannot be assigned to MyException<Number> although Integer is a subclass of Number. Therefore, a MyException<Integer> could not be caught by defining a catch block with MyException<Number>.

Be aware that this limitation also effects inner classes. The following code will produce a compile error:

public class MyClass<T> {
  private class MyInnerException extends Exception { // won't compile    
    ..
  }
}

It is not possible to define a (non generic) exception class inside a generic class. This is a bit strange because the exception itself has no generic type parameter. I cannot think of a reason why this should cause problems (if you can, please tell me!). Making the inner class static solves the compile error.

Generic type parameters can be thrown

While exception are not allowed to contain generic type parameters it is perfectly fine to throw generic types (if they extend Throwable). The following code compiles fine:

public <T extends Exception> void throwIt(T t) throws T {
  throw t;
}  

public void catchIt() {
  try {
    throwIt(new Exception());
  } catch (Exception e) {
    ..
  }
}

However, it is not possible to use generic type parameters in catch blocks. So the next snippet won't compile:

public <T extends Exception> void throwIt(T t) throws T {
  throw t;
}  

public <T extends Exception> void catchIt(T t) {
  try {
    throwIt(t);    // fine
  } catch (T e) {  // compile error
    ..
  }
}

The reason for this is again type erasure.

Comments

  • Joy C - Tuesday, 7 March, 2017

    Good article. (not sure why there aren't many comments here)

Leave a reply