第七章--第二节:错误和异常的处理
第七章:软件构造的健壮性
第二章:错误和异常的处理
问题一:Java中的错误和异常
java.lang.Throwable 包含:java.lang.Exception、java.lang.Error。
内部错误(Error):程序员通常无能为力,一旦发生,想办法让程序优雅的结束
异常(Exception):你自己程序导致的问题,可以捕获、可以处理
问题二:错误(Error)
分类:
- User input errors 用户输入错误
- Device errors 设备错误
- Physical limitations 物理限制
典型的错误:
问题三:异常的处理(既然Error我们无能为力,那就转向关注我们能处理的Exception)
1.异常:程序执行中的非正常事件,程序无法再按预想的流程执行。
2.异常处理:
- 将错误信息传递给上层调用者,并报告“案发现场”的信息。
- return之外的第二种退出途径
- 若找不到异常处理程序,整个系统完全退出
*例:对比使用异常处理和不使用异常处理
①不使用异常处理
②使用异常处理
3.异常的分类
- 运行时异常(Exceptions that derive from RuntimeException):由程序员处理不当造成
- 其他异常:由外部原因造成(是程序员无法完全控制的外在问题导致的)
问题四:Checked and unchecked exceptions(异常被谁check?——编译器、程序员)
1.Checked exception:编译器可帮助检查你的程序是否已抛出或处理了可能的异常
**例:
checked exception:
①
②
- throws:声明“可能会发生异常”
- throw:抛出异常
- try,catch,finally:捕获并处理异常
2.Unchecked exception(Error + RuntimeException):程序员对此不能做任何是事情,不得不重写你的代码。(不需要在编译的时候用try…catch等机制处理)
常见的Unchecked exception:
- ArrayIndexOutOfBoundsException: thrown by JVM when yourcode uses an array index, which is outside the array's bounds.
- NullPointerException: thrown by the JVM when your codeattempts to use a null reference where an object reference isrequired.
- NumberFormatException: Thrown programmatically (e.g., byInteger.parseInt()) when an attempt is made to convert a stringto a numeric type, but the string does not have the appropriateformat.
- ClassCastException: thrown by JVMwhen an attempt is made to cast an object reference fails.
- IllegalArgumentException: thrown programmatically to indicatethat a method has been passed an illegal or inappropriate argument.You could re-use this exception for your own methods.
- IllegalStateException: thrown programmatically when a methodis invoked and the program is not in an appropriate state for thatmethod to perform its task. This typically happens when a method isinvoked out of sequence, or perhaps a method is only allowed to beinvoked once and an attempt is made to invoke it again.
- NoClassDefFoundError: thrown by the JVM or class loader whenthe definition of a class cannot be found.
**例:
unchecked exception:
3.如何决定使用哪种异常处理?
当要决定是采用checked exception还是Uncheckedexception的时候,问一个问题:“如果这种异常一旦抛出,client会做怎样的补救?”
选用Unchecked exception:客户端代码不能做任何事情
选用Checked exception:客户端代码将基于异常的信息采取一些有用的恢复措施。
- 如果客户端可以通过其他的方法恢复异常,那么采用checked exception;
- 如果客户端对出现的这种异常无能为力,那么采用unchecked exception;
- (异常出现的时候,要做一些试图恢复它的动作而不要仅仅的打印它的信息。)
- 尽量使用unchecked exception来处理编程错误:因为uncheckedexception不用使客户端代码显式的处理它们,它们自己会在出现的地方挂起程序并打印出异常信息。
- 如果client端对某种异常无能为力,可以把它转变为一个unchecked exception,程序被挂起并返回客户端异常信息
- 不要创建没有意义的异常,client应该从checked exception中获取更有价值的信息(案发现场具体是什么样子),利用异常返回的信息来明确操作失败的原因。– 如果client仅仅想看到异常信息,可以简单抛出一个unchecked exception:throw new RuntimeException("Username already taken");
- 错误可预料,但无法预防,但可以有手段从中恢复,此时使用checkedexception;如果做不到这一点,则使用unchecked exception
总结:– Checked exception应该让客户端从中得到丰富的信息。
– 要想让代码更加易读,倾向于用unchecked exception来处理程序中的错误。
问题五:通过throws声明Checked Exceptions
- 使用throws声明异常:此时需要告知你的client需要处理这些异常,如果client没有handler来处理被抛出的checked exception,程序就终止执行。
- 程序员必须在方法的spec中明确写清本方法会抛出的所有checked exception,以便于调用该方法的client加以处理
- 在使用throws时,方法要在定义和spec中明确声明所抛出的全部checked exception,没有抛出checked异常,编译出错,Unchecked异常和Error可以不用处理。
异常中的LSP原则:
- 如果子类型中override了父类型中的函数,那么子类型中方法抛出的异常不能比父类型抛出的异常类型更广泛
- 子类型方法可以抛出更具体的异常,也可以不抛出任何异常
- 如果父类型的方法未抛出异常,那么子类型的方法也不能抛出异常。
- 其他的参考第五章第二节的LSP
问题六:用throw抛出一个异常
例:你要抛出一个EOFException,你可以:
- 利用Exception的构造函数,将发生错误的现场信息充分的传递给client。
步骤:
- 找到一个能表达错误的Exception类/或者构造一个新的Exception类
- 构造Exception类的实例,将错误信息写入
- 抛出它
(一旦抛出异常,方法不会再将控制权返回给调用它的client,因此也无需考虑返回错误代码)
问题七:创建异常类(自定义异常)
如果JDK提供的exception类无法充分描述你的程序发生的错误,可以创建自己的异常类。
*例:自定义checked异常
*例:自定义Unchecked异常
①
②
*例:自定义异常可以包含更多的信息
问题八:捕获异常
模式:
一般的原则:
- 尽量在自己这里处理,实在不行就往上传——要承担责任!;但有些时候自己不知道如何处理,那么提醒上家,由client自己处理(使用throws关键字)
- 如果父类型中的方法没有抛出异常,那么子类型中的方法必须捕获所有的checked exception
- 子类型方法中不能抛出比父类型方法更多的异常!
获取异常的细节:
e.getMessage():to get thedetailed error message (if there is one)
e.getClass().getName():to get the actual type of theexception object.
问题九:Rethrowing and ChainingExceptions
含义:本来catch语句下面是用来做exception handling的,但也可以在catch里抛出异常
目的:更改exception的类型,更方便client端获取错误信息并处理
*例:
(但这么做最好也要保留跟原因):
问题十:Finally语句
场景:当异常抛出时,方法中正常执行的代码被终止;但如果异常发生前曾申请过某些资源,那么异常发生后这些资源要被恰当的清理,所以需要用finally语句。
***例:
①:
②:
③:
也可以没有catch,直接用finally