这回我们来说说Java的异常:
我们用一个图来开始:
可以发现,所有的异常都是由Throwable继承而来的,下面分为了Error和Exception。
其中Error类曾是结构描述了额Java运行时系统的内部错误和资源耗尽错误。这种错误程序员无能为力,不管了。
所以我们需要关注的是Exception层次的错误,派生与RuntimeException的异常包含以下几种情况:
1)错误的类型转换
2)数组访问越界
3)访问null指针
不是派生于RuntimeException的异常包括:
1)试图在文件尾部后面读取数据。
2)试图打开一个不存在的文件
3)一招给定的字符串查找Class对象,而这个字符串表示类并不存在
还有无法找到类的错误,以及不支持克隆的错误。
Java语言将派生于Error类或RuntimeException类的所有异常称为非受查异常,所有其他的异常称为受查异常。
方法应该在其首部声明所有可能抛出的异常,举个例子啊~
public FileInputStream(String name) throws FileNotFoundException
但也不能将所有可能抛出的异常都进行声明。以下四种情况,应该抛出异常:
1.调用一个抛出受查异常的方法,例如FileInputStream构造器
2.程序运行过程中发现错误,并且利用throw语句抛出一个受查异常
3.程序出现错误,例如a[-1] = 0 会抛出一个ArrayIndexOutOfBoundException这样的
4.Java虚拟机和运行时库出现的内部错误。
对于那些可能被他人使用的Java方法,我们可以这样:
class MyAnimation{
...
public Image loadImage(String s)throw IOException
//假如一个方法可能有多个受查异常类型,我们可以这样
public ...(String)throw FileNotFoundException,EOFException
}
创建异常类:
在程序中,我们很可能会遇见任何标准异常类都没有能充分描述清楚的问题。这种情况下,就需要我们创建自己的异常类。我们只需要定义一个派生于Exception,或者派生于Exception子类的类例子如下:
class FileFormatException(){}
public FileFormatException(String gripe)
{
super(gripe);
}
现在,我们就可以抛出自己的异常啦:
String readData(BufferedReader in)throws FileFormatException{
...
while(...)
{
if(ch == -1)
{
if(n<len) throw new FileFormatException();
}
...
}
return s;
}
上面我们说了,如何抛出一个异常。很简单,但是我们还需要学习下关键内容,即如何去捕获异常:
我们需要使用try/catch语句去捕获异常,如下所示:
try
{
code; more code; more more code;
}
catch(ExceptionType e)
{
handler for this type
}
如果在try语句块中的任何代码抛出了一个在catch子句中说明的异常类,那么:
1.程序将跳过try语句块的其余代码。
2.程序将执行catch子句中的处理器代码。
值得注意的是,如果方法中的任何代码抛出了一个在catch子句中没有声明的异常类型,那么这个方法就会异常退出。
有时候异常并不是一个,如何捕获多个异常呢?
try
{
code that might throw exception
}
catch(FileNotFoundException e)
{
emergency action for missing files
}
catch(UnknowHostException)
{
emergency action for unknown hosts
}
catch(IOException e)
{
emergency action for all other I/O problems
}
在java7中同一个catch可以捕获多个异常类型,只是中间要用一个 | 分开。
比如 FileNotFoundException | UnknowHostException e 这样。
一种“优雅”地抛出异常的方法:
在catch子句中可以抛出一个异常,这样做的目的是改变异常的类型。但是异常类型往往很多,比如执行servlet代码时候,可能不想知道发生错误的细节,但是希望明确的知道servlet是否有问题。
看个例子:
try
{
access the database;
}
catch(SQLException)
{
throw new ServletException("database: " + e.getMessage());
}
这里,ServleException用带有异常信息的文本构造器来构造。
不过,还有一种更“优雅”的处理方法,并且将原始异常设置为新异常的“原因”:
try
{
access the database
}
catch(SQLException e)
{
Throwable se = new ServletException("database error");
se.initCause(e);
//当捕获到异常是,可用 Throwable e = se.getCause();
//重新得到异常
throw se;
}
强烈建议用这种包装技术,这样可以让用户抛出子系统的高级异常,而不会丢失原始异常的细节。