Java中的异常,断言,日志
异常处理的重要性
1.我们为什么要处理异常
当程序出现错误时,用户往往会感觉到很不爽,由于程序的错误或一些外部环境,导致用户的工作丢失。那么用户就不会继续用这个程序了。为了尽量避免这类事情发生,我们至少应做到:
①向用户通知错误。
②保存所有的工作
③允许用户妥善退出程序。
2.当出现异常后程序怎样处理
用户希望在出现异常后,程序能采取合理的行为。因此程序应做到:
①返回到一种安全状态,能让用户执行其他命令。
②保存所有工作,让用户妥善退出程序。
3.在Java中出现异常后程序以怎样方式执行
当某个方法出现异常后,它就不能通过正常的途径退出程序,而是通过另一个路径,在这种情况下,方法不会返回任何值,而是抛出一个封装了错误信息的对象。同时,异常处理机制将会搜索能处理这种异常的异常处理器。
异常层次结构
其中粉色的表示检查型异常,可以被声明;RuntimeException和Error是非检查型异常,不可以被声明。
派生于RuntimeException的异常包括
1.错误的强制类型转换。
2.数组访问越界。
3.访问null指针
通常出现这种异常一定是程序员自己的问题,是完全可以在编程时避免的。
而派生于其他类的异常包括:
1.超越文件末尾读取数据
2.打开一个不存在的文件
1.检查型异常与非检查型异常
检查性异常是编译器要检查这一类异常,检查目的一方面是该类异常发生难以避免,另一方面是让开发人员去解决这种异常。故称为必须处理异常。如果不处理这类异常,编译器会报错。例如:你读取文件的代码本身没有错误,但运行时因为文件找不到而抛出FileNotFoundException,如果不处理程序肯定出错。
非检查型异常:
编译器不会检查这种异常,
特别需要说明的是:子类覆盖了超类的一个方法,子类中声明的检查型异常不能比超类更通用,子类可以抛出更特定的异常,或者根本不抛出异常。
自定义异常
你的代码可能会遇到任何标准异常类都无法描述清楚的问题,此时可以自定义异常类。
通常这个自定义异常类包含两个异常类
- 默认构造器
- 包含详细描述信息的构造器
class FileFormatException extends IOException
{
public FileFormatException{}
public FileFormatException(String gripe){super(gripe);}
}
捕获异常
如果try语句块抛出了catch子句的异常类,那么
- 程序跳出try语句块其余代码
- 程序执行catch子句中的处理器代码
finally子句
代码抛出异常时,就会停止处理这个方法中剩余的代码,如果方法获得了只有他自己知道的本地资源,这些资源必须清理,这样就会有问题,此时需要finally子句。
try-with-Resources语句
try(Resource res=...){
work ...
}catch...
假设资源是实现了AutoCloseable接口的类,则这个语句可以自动关闭资源,而不用写finally子句那么麻烦。
这个语句在正常退出或者存在一个异常时,都会调用close方法。
此语句还可指定多个资源。
如果try语句抛出一个异常,而且close也抛出一个异常,这会带来一个难题,而此语句可以很好处理这个情况,原来的异常会重新抛出,而close抛出的异常会被自动捕获。并由addSuppressed方法增加到原来的异常中。
使用异常的技巧
异常处理不能代替简单的测试
捕获异常所花费的时间较多,因此原则是只有在异常情况下才使用异常
不要过分细化异常
try
{
for(int i=0;i<100;i++){
..
}
}catch(IOException e){
}catch(EmptyStackException e){
}
不要压制异常
有些方法可能100年才抛出一个异常,如果你只想关闭该异常,可以在catch语句中什么也不做。
但一旦出现异常,你很难发现问题。