- 论坛徽章:
- 0
|
1.java中的异常层次结构:
Throwable下层分成两个分支: Error和Exception.
Exception下层分成两个分支: IOException和RuntimeException
Error类层次结构描述了java运行时系统的内部错误和资源耗尽的错误.应用程序不应该抛出这中类型的对象.如果出现这样的内部错误,除了通知用户,并尽力使程序安全地终止之外,再也无能为力了.
Exception划分两个分支的规则是:由于程序错误导致的异常属于RuntimeException.曾经能够正确运行,而由于某些情况(例如 I/O错误)导致的异常不属于RuntimeException.
一条相当有道理的规则"如果出现RuntimeException异常,就一定是你的问题".
java语言规范将派生于RuntimeException类或Error类的所有异常称为"未检查异常",其他的异常称为"已检查异常". 编译器将核查是否为所有已检查异常提供异常处理器.
2.声明已检查异常
一个方法不仅要告诉编译器要返回什么值,还要告诉编译器有可能发生什么错误.例如,一段读取文件的代码知道有可能读取的文件不存在,或者内容为空,因此,试图处理文件信息的代码就需要通告编译器可能抛出IOException类型的异常.
如果一个方法有可能抛出多个已检查异常,就必须再方法的首部列出所有的异常类.每个异常类之间用逗号(,)隔开.如下:
class MyAnimation
{
...............
public Image loadImage(String s) throws EOFException , MalformedURLExceptiom
{
...................
}
}
3.如何抛出异常
现在,我们假设在程序代码中,一个为readData的方法正在读取一个首部具有下列信息的文件:
Content-length:1024
然后,读到733个字符之后文件就结束了,此时.我们认为这是一种非正常的情况,希望抛出一个异常.
首先要决定应该抛出什么类型的异常,将上述异常归结为IOException是一个很好的选择,仔细阅读Java API文档之后会发现,EOFException异常的描述是"在输入过程中,遇到一个未预期的EOF后的信号".这正是我们要抛出的异常.下面就是抛出这个异常的语句:
throw new EOFException();
或者这样书写:
EOFException e=new EOFException();
throw e;
下面将这些代码放在一起:
String readData(Scanner in) throws EOFException
{
....
while(...)
{
if(!in.hasNext())//EOF encountered
{
if(n
throw new EOFException();
}
........
}
return s;
}
EOFException类还有一个构造器,它需要一个字符串型参数.这个构造器可以更加细致的描述异常的出现情况.
String gripe="Content-length;"+len+",Received:"+n;
throw new EOFException(gripe);
在前面已经看到,对于一个已经存在的异常类,将其抛出非常容易.在这种情况下:
1.找到一个合适的异常类.
2.创建这个类的一个对象.
3.将对象抛出.
一旦方法抛出异常,该方法就部可以返回到调用者了,这也意味着不必为返回的默认值或错误代码担忧了.
4.创建异常类
在程序中可能会遇到任何标准异常类都没有能够充分描述清楚的问题.于是创建自己的异常类就是一件顺利成章的事情了.我们学要做的只是定义一个派生于Exception的类,或者派生于Exception子类的类.例如:定义一个派生于IOException的类.习惯上,定义的类应该包含两个构造器,一个是默认的构造器,另一个是带有详细描述信息的构造器(超类Throwable的ToString方法将会打印出这些详细信息,这对于调试代码来说是很方便的)
class FileFormatException extends IOException
{
public FileFormatException{}
public FileFormatException(String gripe)
{
super(gripe);
}
}
现在,就可以抛出自己定义的异常类型了.
String readData(BufferedReader in) throws FileFormatException
{
.......
while(...)
{
if(ch==-1)//EOF encountered
{
if(n
throw new FileFormatException();
}
.......
}
return s;
}
5.捕获异常
捕获异常,必须设置try/cacth语句块.
try
{
code
more code
more code
}
catch(Exception e)
{
handle for thiss type
}
如果try语句块中的任何代码抛出一个catch子句中指定的异常类,那么:
1)程序将跳过try语句块中其余的代码.
2)程序将执行catch子句中的处理器代码.
如果在try语句块中的代码没有抛出任何异常,那么程序跳过catch子句.
如果方法中的任何代码抛出一个在catch子句中没有声明的异常类型,那么这个方法将立刻退出.
6.捕获多个异常
在一个try语句块中可以捕获多个异常类型.并对不同类型的异常做不同的处理.如下:
try
{
code that might throw exceptions
}
catch(MalformedURLException e1)
{
emergency action for malformed URLs
}
catch(UnknownHostException e2)
{
emergency action for unknown hosts
}
catch(IOException e3)
{
emergency action for all other I/O problems
注意: 异常对象(e1,e2,e3)可能包含着与异常本身有关的信息,要想获得对象的更多信息,可以试着使用e3.getMessage()得到详细的错误信息(如果有的话).或者使用e3.getClass().getName()得到异常对象得实际类型.
7.再次抛出异常
在一个catch子句中,也可以抛出一个异常,这样做得目的是希望改变异常的类型.如果开发一个供其他程序远使用的子系统,那么,用于表示子系统故障的异常类型可能会产生多种解释,ServleException就是这样一个异常类型.执行servlet的代码可能部希望知道发生错误的细节原因.但希望明确知道servlet是否有故障.
下面给出捕获异常并将它再次抛出的基本方法.
try
{
access the database
}
catch (SQLException e)
{
throw new ServletException("database error:"+e.getMessage());
}
这里 ,ServleException用带有异常的消息文本来构造.
try
{
access the database
}
catch(SQLException e)
{
Throwable se= new ServletException("database error");
se.setCause(e);
throw se;
}
当捕获到异常时,就可以使用下面这条语句得到原始异常:
Throwable e=se.getCause();
强烈建议使用这种包装技术.它允许用户抛出子系统中得高级异常.而不会丢失原始异常的细节.
8.finally子句,不管是否有异常被抛出,finally子句中的代码都会执行.
待续..............................
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/31513/showart_279382.html |
|