5

I know that I can't throw or catch instances of generic class in Java,for example ,the following code compiles wrongly:

public static <T extends Throwable> void test(Class<T> t){
    try{
        //do work
    }
    catch (T e){// ERROR--can't catch type variable
    Logger.global.info(...)
    }
}

Would anyone can explain the exactly reason for Java to forbidden throw or catch instances of generic class?

J.zhou
  • 163
  • 6

2 Answers2

4

You can't catch a generic exception, because the Java Language Specification explicitly forbids it. In 14.20 The try statement it says:

It is a compile-time error if a type variable is used in the denotation of the type of an exception parameter.

The section does not explain why, but the most like reason is that <T extends Throwable> is erased to Throwable, so your code would actually be compiled as if it was:

public static void test(Class<? extends Throwable> t){
    try{
        //do work
    }
    catch (Throwable e){
    Logger.global.info(...)
    }
}

This is not the intent expressed by your code (and very likely not what you want), therefor the language specification explicitly forbids it.

Note that throwing generic exceptions is allowed, but this is usually only relevant in the context of having some wrapper around another method that throws the exception.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
1

You can not do this because the 'generic type erasure'. The generic information is lost after the compile time, after generate the bytecode class file there are not any generic information and at compile time you have not specified the concrete type for generic T.

See this code for type erasure check, the result is Equal:

A

package a;


public class A {

    public static void main(String[] args) {

        final B<String, Integer> b = new B<String, Integer>();

        b.check();
    }

}

B

package a;

import java.util.ArrayList;
import java.util.List;

public class B<T, E> {

    public void check(){

        final List<T> listT = new ArrayList<T>();
        final List<E> listE = new ArrayList<E>();

        if (listT.getClass().equals(listE.getClass())) {
            System.out.println("Equal");
        }
    }

}

See this link too: http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html#cannotCatch

Francisco Hernandez
  • 2,378
  • 14
  • 18
  • 1
    Your generic types are unbound, so it is clear why they be erased to `Object`, but OPs parameter will be erased to `Throwable` which can be catched. So this answer doesn't explain why this is still prohibited. – Tom Nov 14 '15 at 08:50
  • Have you seen the last link? is a generic restriction on exceptions and Throwables, and its related to both exception mechanism and type erasure – Francisco Hernandez Nov 14 '15 at 08:55
  • This also doesn't explain why `catch (T t)` (with `T` being ``) isn't allowed. And their erasure example shows a different aspect: own generic classes which extend `Exception`. This is something different. – Tom Nov 14 '15 at 09:12
  • @Tom Your code would express the intent to only catch T, while the actual byte code would catch `Throwable`, that sounds like a very good reason to disallow it. The second example in the linked tutorial and its code express the exact same problem (except they use `T extends Exception` instead of `T extends Throwable`. That paragraph describes **three different** aspects of generics and exceptions. – Mark Rotteveel Nov 14 '15 at 09:25