文章的标题看似自相矛盾,然而我在“正确”二字上打了引号。咱们来看一个例子,关于Java异常处理(Exception Handling)的一些知识点。java
看下面这段程序。方法pleaseThrow接受一个Exception的实例,而后简单地将该实例抛出。而后调用这个方法时,我传入了一个SQLException的实例。由于pleaseThrow的调用包裹在一个try catch块里,less
问题:plesseThrow方法抛出的SQLException能够成功被catch住么?ui
public class ExceptionForQuiz<T extends Exception> { private void pleaseThrow(final Exception t) throws T { throw (T) t; } public static void main(final String[] args) { try { new ExceptionForQuiz<RuntimeException>().pleaseThrow(new SQLException()); } catch( final SQLException ex){ System.out.println("Jerry print"); ex.printStackTrace(); } } }
答案:上面这段代码有语法错误,不能经过编译!code
咱们来一步步分析。开发
Java类ExceptionForQuiz<T extends Exception>使用了一个泛型语法,T extends Exception意思是这个泛型类实例化的时候,传入的类型参数T必须是Exception以及它的子类。编译器
我在实例化类ExceptionForQuiz时,传入的类型参数是RuntimeException。io
RuntimeException在Java里是一种Unchecked异常,即便一个方法运行时可能会抛出RuntimeException,也不须要开发人员在方法前用代码显式声明。编译
看JDK RuntimeException的注释说的很清楚:Unchecked exceptions do NOT need to be declared in a method or constructor's clause if they can be thrown by the execution of the method or constructor.class
这个做者Frank Yellin必定是个大牛。泛型
由于泛型是 Java 1.5 版本才引进的概念,关于泛型有一个类型擦除的概念,即**泛型信息只存在于代码编译阶段,编译以后的代码里,与泛型相关的信息会被擦除掉。**好比以前泛型类中的类型参数部分若是没有指定上限,像这种写法<T>, 则会被转译成普通的Object类型。若是指定了上限如<T extends String>则类型参数就被替换成类型上限。
为了简化起见,咱们先把代码里的try catch块去掉。
下面是从ExceptionForQuiz.class反编译以后的代码:
咱们从上图能观察到,方法pleaseThrow和雷ExceptionForQuiz的泛型参数RuntimeException已经被擦除掉了。pleaseThrow这个方法能抛出的异常类型已经被擦除成为Exception了。
使用javap观察编译生成的字节码,一样能发现类型参数RuntimeException被擦除的事实:
看第二个红色高亮区域:Exceptions: throw java.lang.Exception
如今咱们来看编译器会报什么错误消息:Unreachable catch block for SQLException. This exception is never thrown from the try statement body.
根据异常类型擦除的事实,这个错误消息是合理的,由于pleaseThrow方法的声明如今只能抛出类型为Exception的异常,因此第14行的catch永远也没有办法接收到类型为SQLException的异常,因此编译器抛出错误。
如何消除掉这个编译器错误呢?把第14行的SQLException改为RuntimeException便可。
可是这样的话,虽然消除了语法错误,可是方法pleaseThrow抛出的SQLException没有办法被catch住,会报运行时错误:
如何把pleaseThrow抛出的SQLException也用catch语句接住呢?将第14行的RuntimeException改为全部异常的超类:Exception。
再次执行,此次既没有语法错误,也没有运行时错误了:SQLException已经成功地被第14行的catch语句捕捉住了。
要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码: