关于Java中的异常处理:
常见的错误:
1.用户输入错误
2.设备错误
3.物理限制
4.代码错误
异常分类:
在Java中,异常对象都是派生于Throwable类的一个实例。
Error:
描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。
Exception:
可以分为两种,一种为RuntimeException:
错误的类型转换;
数组访问越界;
访问null指针。
非派生于RuntimeException的异常:
试图在文件尾部后面读取数据;
试图打开一个不存在的文件;
试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在。
Java语言规范将派生于Error类或RuntimeException类的所有异常称为非受查(unchecked)异常,所有其他的异常称为受查(checked)异常。
什么时候该抛出异常呢?
1)调用一个抛出受查异常的方法。
2)程序运行过程中发现错误,并且利用throw语句抛出一个受查异常。
3)程序出现错误
4)Java虚拟机和运行时库出现的内部错误
一个方法必须声明所有可能抛出的受查异常,而非受查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。
如何抛出异常呢?
1)找到一个合适的异常类
2)创建这个类的一个对象
3)将对象抛出
捕获异常:
捕获异常,必须设置try/catch语句。
如果在try语句块中的任何代码抛出了一个在catch子句中说明的异常类,那么就有:
1)程序将跳过try语句块的其余代码
2)程序将执行catch子句中的处理器代码
如果在try语句块中没抛出任何异常,那么程序跳过catch子句。
如果方法中的任何代码抛出了一个在catch子句中没有声明的异常类型,那么这个方法就会立刻退出。
关于异常中的再次抛出:
try{
}
catch(SQLException e)
{
throw new ServletException("databse error:" + e.getMessage());
}
//下面还有一种更好的处理方法,并且将原始异常设置为新异常的“原因”:
try{
acess the database
}
catch(SQLException e)
{
Throwable se = new ServletException("database error");
se.initCause(e);
throw se;
}
//当捕获到异常时,就可以使用下面这条语句重新得到异常:
Throwable e = se.getCause();
//这样可以让用户抛出子系统中的高级异常,而不会丢失原始异常的细节。
使用异常机制的技巧:
1.异常处理不能替代简单的测试,例如退栈之前,首先要查看栈是否为空。
if(!s.empty()) s.pop();
//下面是强行退栈后捕获EmptyStackException异常
try
{
s.pop();
}
catch(EmptyStackException e){
}
//调用isEmpty只要646ms,捕获EmptyStackException时间需要21739ms,后者所需时间大大超过前者。
所以,只在异常情况下使用异常机制。
2.不要过分地细化异常
有必要将整个任务包装在一个try语句块中,这样,当任何一个操作出现问题时,整个任务都可以取消。
//对比一下
PrintStream out;
Stack s;
for(i = 0; i < 100; i++)
{
try
{
n = s.pop();
}
catch(EmptyStackException e)
{
//stack was empty
}
try
{
out.writeInt(n);
}
catch(IOException e)
{
//problem writing to file
}
}
//上面这种方式会使代码量急剧膨胀
try
{
for(i = 0; i < 100; i++)
{
n = s.pop();
out.writeInt(n);
}
}
catch(IOException e)
{
//problem writing to file
}
catch(EmptyStackException e)
{
//stack was empty
}
下面的方法就使代码更清晰。
3.利用异常层次结构。
不要只抛出RuntimeException异常。应该寻找更加适当的子类或创建自己的异常类。
不要只捕获Throwable异常,否则,会使程序代码更难度、更难维护。
将一种异常转换成另一种更加适合的异常时不要犹豫。比如,在解析某个文件中的一个整数时,捕获NumberFormatException异常,然后将它转换成IOException或MySubsystemException的子类。
4.不要压制异常。
5.在检测错误时,"苛刻"比放任好
检测到错误时,不要担心抛出异常。例如无效的参数调用一个方法时,返回一个虚拟的数值,还是抛出一个异常。比如,栈空时,是返回一个null,还是抛出一个异常?我们认为:在出错的地方抛出一个EmptyStackException的异常要比在后面抛出一个NullPointerException异常更好。
6.不要羞于传递异常
例如,FileInputStream构造器或readLine方法,这些方法就会本能地捕获这些可能产生的异常。其实,传递异常要优于捕获这些异常
让高层次的方法通知用户发生了错误,或者放弃不成功的命令更加适宜。
错的地方抛出一个EmptyStackException的异常要比在后面抛出一个NullPointerException异常更好。
6.不要羞于传递异常
例如,FileInputStream构造器或readLine方法,这些方法就会本能地捕获这些可能产生的异常。其实,传递异常要优于捕获这些异常
让高层次的方法通知用户发生了错误,或者放弃不成功的命令更加适宜。
5、6归结为“早抛出,晚捕获”。