关键字: 异常通告(throws)throwtrycatchRuntimeException不可检查(Unchecked)异常 可检查(Checked)异常
Java编程中的异常处理是一个很常见的话题了几乎任何一门介绍性的Java课程都会提到异常处理不过我认为很多人其实并没有真正掌握正确处理异常情况的方法和策略最多也就不过了解个大概知道点概念本文就对三种不同程度和质量的Java异常处理进行了讨论所阐述的处理异常的方式按手法的高下分为
好不好和恶劣三种
同时向你提供了一些解决这些问题的技巧
首先解释一些java异常处理中必须搞清楚的定义和机制Java语言规范将自Error类或RuntimeException类衍生出来的任何违例都称作不可检查(Unchecked)异常;其他所有异常则称作可检查(Checked)异常
所谓可检查异常是指我们应该自行处理的异常至于处理的手段要么加以控制(try catch)要么通告(throws)他们有可能产生通常应捕捉那些已知如何处理的异常而通告那些不知如何处理的异常
而对那些不可检查异常来说他们要么在我们的控制之外(Error)要么是我们首先就不该允许的情况(RuntimeException)
至于异常的指定Java的规则非常简单一个方法必须通告自己可能产生的所有可检查异常编写自己的方法时并不一定要通告出方法实际可能产生的每一个异常对象要想理解什么时候必须要方法的throws丛句来通告异常就必须知道对一个异常来说他只有可能在下面四种情况下才会产生
.调用了可能产生异常的方法比如BufferedReader类的readLine方法该方法通告javaioIOException异常
.侦测到一个错误并用throw语句产生异常
.出现一个编程错误比如a[] =
.Java产生内部错误
如果出现头两种情况之一必须告诉打算使用自己方法的人假如使用这个方法可能造成一个异常的产生(即在方法头上使用throws)一个简单的记忆方法
只要含有throw就要通告throws如果一个方法必须同时处理多个异常就必须在头内指出所有异常就像下例展示的那样用逗号对他们进行分割
class Animation {public Image loadImage(Strint s) throws EOFExceptionMalformedURLException {…………}}
然而我们不需要通告内部java错误也不应该通告自RuntimeException衍生出来的异常
好异常处理
好异常处理提供了处理程序错误的统一机制事实上Java语言通过向调用者提出异常警告的方式而显着地提升了软件开发中的异常处理能力这种方式把Java语言中的方法(method)进行了扩展和增强使之包括了自身的错误条件下面就让我们看一个例子这个例子说明了这种情况
以下是FileInputStream构造器之一的原型
public FileInputStream(String name) throws FileNotFoundException Java
的方法和构造器必须声明他们在被调用时可能扔出的异常采用的关键字就是throws这种在方法原型中出现的异常提示增加了编程的可靠性
显而易见这种方式是向方法的调用者提示了可能出现的异常条件这样调用者就可以对这些异常作出适当的相应处理以下代码示意我们是如何捕获并且处理FileNotFoundException 这一异常的
try { FileInputStream fis = new FileInputStream(args[]); // other code here } catch (FileNotFoundException fnfe) { Systemoutprintln(File: + args[] + not found Aborting); Systemexit(); }
Java异常处理还有其他一些优秀的特性这就是可检查异常用户定义异常和在JDK 中推出的新型Java记录API(Java Logging API)javalangException的所有子类都属于可检查异常可检查异常(checked exception)是扔出该异常的方法所必须提示的异常这种异常必须被捕获或者向调用者提示用户定义异常(Userdefined exceptions)是定制的异常类这种异常类扩展了javalangException类优良的Java程序规定定制异常封装报告和处理他们自己独有的情况最新的Java记录API(logging API)则可以集中记录异常
不好 Java异常处理
不好的一面包括两种情况滥用不可检查异常(unchecked exceptions)和滥用catchall构造器等这两种方式都使得问题变得复杂起来
有一种类别的异常属于RuntimeException的子类这种异常不会受到编译器的检查比如NullPointerException和 ArrayStoreException就是这种类型异常的实例程序员可以对RuntimeException进行子类化以回避检查异常的限制从而便于产生这些异常的方法为其调用者所使用
专业的开发团队应当只允许在很少的情况下才可以这样做
第二种异常处理的陋习是catchall构造器所谓的catchall 构造器就是一种异常捕获代码模块它可以处理所有扔给它的可能异常
以下是catchall处理器的实例
try { // code here with checked exceptions } catch (Throwable t) { tprintStackTrace(); }
我得承认我自己在编写一般程序的时候就曾经用过这种技术但是在编写关键程序的时候这种类型的构造器一定要避免使用除非他们被授权可以和中央错误处理器联合使用才可以这样做
除此之外catchall构造器不过只是一种通过避免错误处理而加快编程进度的机制
异常处理的一个不足之处是难以采用优良的错误处理策略从低容内存状态恢复写入错误和算法错误等异常情况都不是轻易能得到解决的你可以尝试一下循环垃圾收集和提醒用户等常用技术来应付以上的局面
恶劣
和许多Java特性及其API类似Java的异常处理机制也有霸王硬上弓类的滑稽错误比方说为了扔出某个异常竟然毫不犹豫地用new关键词为其分配内存就是这样的例子
我自己不知道有多少次就因为犯了这种错误而在严肃的编译器面前屡屡碰壁在这种情况下我们其实都是在伺候语言而不是让语言为我们所用还有我们碰到的OutOfMemoryErrors就是异常处理的缺陷这一处理过程是
使用finally模块关闭文件解析异常以得到出现问题的方法和代码行在这一过程之内最大的缺陷是需要捕获OutOfMemoryError而这一异常却并不是可检查异常!想想看内存耗尽是相当常见的情况任何与内存使用状态紧密相关的程序都应当捕获和处理这一错误
使用异常时的一些建议
.异常控制的设计宗旨并不是用来代替一些简单的测试只有在异常情况下才使用异常!
.不要过分细化异常不要在每个语句上都加上异常处理最好将整个任务都放在try块内如果其中有一项操作失败可以随即放弃任务
.不要压制异常对于需要通告异常的方法我们可以改用捕捉的方法来将异常强行关闭如果真的出现异常那个异常会被静悄悄的忽略如果觉得产生的异常会非常重要就必须多费些功夫对其进行正确的控制
.不要介意异常的传递如果调用的方法会产生异常比如readLine方法他们天生就能捕捉自己可能产生的异常在这种情况下一种更好地做法是将这些异常传递出去而不是自己动手来捕捉它