Java异常

本文详细解析了Java异常处理机制,包括检查型异常与非检查型异常的区别,如何选择抛出哪种类型的异常,以及如何设计自定义异常类。同时介绍了Throwable、Error与Exception等关键类的作用。

  Throwable
                                                |
                                  ---------------------------------
                                  |                               |
                               Error                     Exception
                                  |                               |
                              ---------               ---------------------------
                              |       |                |                         |
                                              IOException       RuntimeException
                                                      |                          |
                                                 -----------                -----------
                                                 |         |                 |         |
  
                                         Java异常层次结构图
  
  Java中所有的异常类都从Throwable类继承.Error层次描述了Java运行时系统内部错误或资源耗尽错误,应用程序
  不应该抛出该类型的异常对象, 如果出现了这种异常,除了通知用户,并尽力的是程序安全终止外,再也无能为力了
  
  Java的异常体系分为两个分支,一个是从Error与RuntimeException派生的异常(称为未检查异常),另一个是从除
  Error 与RuntimeException之外的派生异常(称为已检查异常),
  [1]一定要对已检查异常提供异常处理器,因为已检查异常是能够预测的,比如包括:
     1.试图在文件尾部后面读取数据,可能会抛出IOException异常
     2.试图打开一个错误格式的URL
     3.试图根据指定字符串查找Class对象,但是该字符串表示的类并不存在
  [2]未检查异常是不可预测的,所以可以不用为未检查异常提供异常处理器("如果出现了RuntimeException异常就
      一定是你的问题"),比如包括:
     1.错误的类型转换
     2.访问空指针
     3.数组访问越界
    
  异常与条件语句的差别:
  虽然条件语句看上去确实跟异常处理差不多,但是异常处理拥有比条件语句更大的处理范围,就是说条件语句不能
  处理的,可以通过异常进行处理,
  比如说:
     内存溢出不可能简单通过条件语句进行判断,只能交由异常处理机制进行处理

 

 

检查型异常和非检查型异常
  现在,主要问题就是抛出检查型异常还是非检查型异常了。检查型异常是Exception的子类(或者Exception类本身),但不包括RuntimeException和它的子类。非检查型异常是RuntimeException和它的任何子类。Error类及其子类也是非检查型的,但是你应该仅着眼于异常,你所做的应该是决定抛出RuntimeException的子类(非检查异常)还是Exception的子类(检查异常)。
  如果抛出了检查型异常(而没有捕获它),那么你需要在方法的throws子句中声明该异常。客户程序员使用这个方法,他要么在其方法内捕获并处理这个异常,要么还在throws子句中抛出。检查型异常强制客户程序员对可能抛出的异常采取措施。
  如果你抛出的是非检查型异常,那么客户程序员可以决定捕获与否。然而,编译器并不强制客户程序员对非检查型异常采取措施。事实上,他们甚至不知道可能这些异常。显然,在非检查型异常上客户程序员会少费些脑筋。
  有一个简单的原则是:
  如果希望客户程序员有意识地采取措施,那么抛出检查型异常。
  一般而言,表示类的误用的异常应该是非检查型异常。String类的chartAt()方法抛出的StringIndexOutOfBoundsException就是一个非检查型异常。String类的设计者并不打算强制客户程序员每次调用charAt(int index)时都检查index参数的合法性。
  另一方面,java.io.FileInputStream类的read()方法抛出的是IOException,这是一个检查异常。这个异常表明尝试读取文件时出错了。这并不意味着客户程序员错误地使用了FileInputStream类,而是说这个方法无法履行它地职责,即从文件中读出下一个字节。FileInputStream类地设计者认为这个意外情况很普遍,也很重要,因而强制客户程序员处理之。
  这就是窍门所在。如果意外情况是方法无法履行职责,而你又认为它很普遍或很重要,客户程序员必须采取措施,那么抛出检查型异常。否则,抛出非检查型异常。
  自定义异常类
  最后,你决定实例化一个异常类,然后抛出这个异常类的实例。这里没有具体的规则。不要抛出用一条字符串信息指出意外情况的Exception类,而是自定义一个异常类或者从已有异常类中选出一个合适的。那么,客户程序员就可以分别为不同的异常定义相应的catch语句,或者只捕获一部分。
  你可能希望在异常对象中嵌入一些信息,从而告诉catch子句该异常的更详细信息。但是,你并不仅仅依赖嵌入的信息来区别不同的异常。例如,你并不希望客户程序员查询异常对象来决定问题发生在I/O上还是非法参数。
  注意,String.charAt(int index)接收一个非法输入时,它抛出的不是RuntimeException,甚至也不是IllegalArgumentException,而是StringIndexOutOfBoundsException。这个类型名指出问题来自字符串索引,而且这个非法索引可以通过查询这个异常对象而找出。
  
结论

  本文的要点是,异常就是意外情况,而不该用于报告那些可以作为方法的正常功能的情况。虽然使用异常可以分离常规代码和错误处理代码,从而提高代码的可读性,但是,异常的不恰当使用会降低代码的可读性。
  以下是本文提出的异常设计原则:
如果方法遭遇了一个无法处理的意外情况,那么抛出一个异常。
避免使用异常来指出可以视为方法的常用功能的情况。
如果发现客户违反了契约(例如,传入非法输入参数),那么抛出非检查型异常。
如果方法无法履型契约,那么抛出检查型异常,也可以抛出非检查型异常。
如果你认为客户程序员需要有意识地采取措施,那么抛出检查型异常。

 

Throwable
├Error
└Exception
│└RuntimeException

 

Throwable 类:

是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。

两个子类的实例,Error 和 Exception,通常用于指示发生了异常情况。通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。

 

Error 是 :

Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。大多数这样的错误都是异常条件。虽然 ThreadDeath 错误是一个“正规”的条件,但它也是 Error 的子类,因为大多数应用程序都不应该试图捕获它。

在执行该方法期间,无需在其 throws 子句中声明可能抛出但是未能捕获的 Error 的任何子类,因为这些错误可能是再也不会发生的异常条件。

 

Exception 类:

Exception及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。

 

RuntimeException类:

Exception的子类,是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。

可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值