JDK 7 代码中对捕获再抛出异常时的处理--即异常类型推断

JDK 发展过程中,第一次变化最大数 JDK1.5,加入了变长参数,泛型。泛型的最大的受益者是集合。JDK7 虽说引进了同时捕获多个异常(Multi-Catch),更聪明一点类型推断,资源的释放等,但我觉得变化还不大。接下来众人期望的 JDK8 的 Lambda 表达式才是激动人心的,恐怕这一特性的大赢家仍是集合。

这样 JDK 才不至于离 C# 太远,纯粹语言上讲,我更景仰 C#,比如它的匿名类型,更不论人家的 Lambda 了。

var person = new { Name = "Unmi", Website = "http://unmi.cc" };
Console.WriteLine(person.Name);

这要到 Scala 中才能见到这种影子。

注: JDK 从 1.5 起就加入了象 Chrome, Firefox 那样的版本党了,所以这个版本也叫做 JDK5,不管是后来的 JDK6, JDK7 等等,其实在命令行下 java -version 显示出来的也还是 1.5.0, 1.7.0_40 这种理智的版本号的。

回过神来,我们要说的是 JDK7 对异常的处理,不讲同时捕获多个异常和 try-with-resource 的处理,而要说的是捕获异常再次抛出时进步,这在某方面得益于 JDK7 类型推断。JDK7 类型推断对于泛型来说,它可以不用这么写

List<String> result = new ArrayList<String>();

而代之以

List<String> result = new ArrayList<>();

JDK7 认为既然前面有 List<String>, 后面何必再重复一遍 <String> 呢。这时 Scala 和 C# 就会笑而不语了,会觉得这样的类型推断还不够彻底,它们能搬出更聪明的 var 关键字。

发散性思维的可怕之处在于一直在做前戏,都快睡着了。切入正题吧。看看 JDK7 是怎么进行异常类型的推断

1. 同一个方法中的代码

在 JDK7 之前下面的代码是可以编译通过的,但 JDK7 编译器不认可

在 JDK7 下报错为:Unreachable catch block for App.SubException2. This exception is never thrown from the try statement body

JDK7 编译器在 1 处能推断出抛出的异常类型是 SubException1, 底下的 catch(SubException2 e2) 就别白费心思啦。

2. 调用抛出异常的方法时

下面的代码在 JDK7 这前是无法通过编译,JDK7 下通过

在 JDK6 下 doSomething() 方法必须声明 throws Exception 抛出 Exception 类型的异常才成,因为它只简单的看到像是在  throw e:Exeption。而 JDK7 编译器在 try doSomethingElse() 推断出 catch(Exception e) 就是一个 RuntimeException 非检测异常类型,所以 doSomething() 方法中可以省去 throws Exception

3. 进一步测试 JDK7 处理异常时到底有多聪明

下面的代码对 JDK7 来说可以通过,糊弄不了它的,也无须为 doSomething() 方法声明 throws Exception

这一段也没问题:

所以可以相信 JDK7 对异常类型的推断还是有一定深度的。

但 JDK7 看到如下的代码同样会傻眼

在 JDK7 下也必须为 doSomething() 加上  throws Exception 声明,只看到 doSomethingElse() 方法的 throws Exception 声明就认定它抛出的是 Exception 类型,而跳过的 throw new RuntimeException() 内容的具体推断。

因此当你在为 catch(Exception e) { throw e; } 后要不要为所在方法加上 throws 声明时,可以查查 try 块中调用的方法有没有声明抛出需检测的异常。当然,有现代化的 IDE 根本不担心这个,按错误提示来办事,通常只需一个简单的快捷键就帮你做好了,但任何时候理解是万岁。

参考:Using Throws and Throw Statements in Java

类别: Java/JEE. 标签: . 阅读(965). 订阅评论. TrackBack.

Leave a Reply

Be the First to Comment!

avatar