1. Java将异常分为两种:Checked异常和Runtime异常,Java认为Checked异常都是可以在编译阶段被处理的异常,所以强制程序处理所有的Checked异常;Runtime异常则无需处理。
2. Java的异常处理机制可以让程序具有更好的容错性,让程序更加健壮。当程序运行出现意外情形时,系统会自动生成一个Exception对象来通知程序,从而实现“业务代码”和“错误处理”相分离。因此我们希望有一种非常强大的if块,可以表示所有的错误情况,让程序一次性处理所有的错误,也就是希望将错误集中处理。
3. try块内声明的变量是代码块局部变量,它只在try块内有效。
4. 有时候,程序在try块里打开了一些物理资源,如数据库连接,网络连接或磁盘文件等,这些物理资源都必须得显式回收。
5. Java的垃圾回收机制不会回收任何物理资源,只回收堆内存中对象所占的资源。
6. 除非在try块、catch块中调用了退出虚拟机的方法,否则不管在try块、catch块中执行怎样的代码,出现怎样的情况,异常处理的finally块总会被执行。
7. 应尽量避免在finally块里执行return或者throw等导致方法终止的语句,因为当Java程序执行try块时遇到return或者throw语句,这两个语句会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找异常处理流程中是否有finally语句块,如果没有,return或者throw立即执行,结束方法;如果有,系统执行finally块---只有当finally块执行完成之后,系统才会再次跳回执行return或者throw语句,如果finally块里面也有return或者throw等导致方法终止的语句,finally块已经终止了该方法,那么try块中的return或者throw语句将不会被执行(try块或者catch块)。
8. Java7之后允许在try关键字之后跟一个圆括号,可以声明或者初始化一个或多个需要在程序结束时关闭的资源,代码如下:
1 try (BufferReader br = new BufferReader(new FileReader("***.java"))) { 2 br.readLine(); 3 }
这样,就不需要finally语句块了,不过BufferReader必须实现Closeable或者AutoCloseable接口才行。
9. Java的异常被分为Checked异常和Runtime异常,其他语言并没有提供Checked异常,Java认为Checked异常都是可以被处理的异常,所以程序必须显式的处理,如果不处理,则无法编译通过。这种设计体现了Java非常严谨的设计哲学,但是大部分的方法总是不能明确的知道如何处理异常,因此只能抛出,而这种方法很普遍,导致降低了程序的生产率和代码的执行效率,这在Java领域是一个比较受争议的问题。
10. 使用throws关键字抛出异常,基本思路是:当前方法不知道如何处理这种类型的异常,那么将之抛出,由调用它的方法去处理,如果main方法也不知道如何处理,也可以抛出,此时异常将交由JVM处理。JVM的处理方法是:打印异常的跟踪栈信息,并终止程序运行,这也是为什么程序遇到异常后自动结束的原因。
1 public static void main(String[] args) throws IllegalAccessException{}
如上,调用main方法的方法或者try catch异常,或者继续抛出。
11. 如此可见,使用Checked异常有两大不便之处:
1>.Java要求显式处理,增加了编程复杂度;
2>.如果该方法被重写,根据继承的基本原则,重写后的方法只能抛出父类方法中异常的子类或者相同;
因此,当程序需要自行抛出异常时,使用Runtime异常更为简洁。当然,如果程序需要在合适的地方对异常进行处理,则一样可以使用try catch来捕获。
12. 使用Runtime异常比较省事,即可以享受“正常代码和错误处理代码分离”,又可以避免使用Checked异常带来的编程繁琐性。因此,C#、Ruby、Python等都没有Checked异常。
13. 使用throw抛出异常
当程序出现错误时,系统会自动抛出异常,除此之外,Java也允许程序自行抛出异常,又throw来完成。异常是一种主观的说法,因为在不同的场合,异常不见得是异常。因此是否要抛出异常,应根据应用的业务需求来决定,而这种与业务需求不符产生的异常,必须由程序员来决定是否抛出,系统无法抛出这种异常。