Java异常处理:
什么是异常:
异常可以看做是运行时的错误,不正常的操作产生的结果等,可能来源于I/O错误,设计逻辑的错误等。
异常处理就是一种用于方便捕捉并进入适当处理过程的手段,可以方便我们的程序设计。
方法:
try{} catch{} finally{} 组合来捕获并处理异常。
其中,try{}用于定义可能产生异常的代码段,catch{}部分是用来处理异常的,而finally{}部分则做一些清理工作。其处理的逻辑是:
1 try中语句在执行中如果没有发生异常,则转到 后继续运行
2 try段中一旦某一条语句发生了异常,则在try段其余的语句不会被继续执行,而是立即转到catch部分进行异常处理。
3 finally段是一个特殊的地方,其中的代码一定会被执行:在没有发生异常的情况下,在try块之后执行;发生异常后,则在符合条件的catch语句段后执行!切记!
4 finally段一般用于完成关闭文件,释放网络套接字,或者其它清理工作。
5 try{} catch{} finally{} 组合中,以下情况都是真确的:
try{} catch{} finally{} 完全版本
try{} catch{} 没有finally{}
try{} finally{} 没有catch{}
但是,如果没有catch{} finally{} ,而只有try{},这时Java语法所不允许的。
注意:
try 和 catch 代码段是不可分割的;
对一个catch 代码段,可以存在多个catch 部分,分别用来捕获不同类型的异常,这些catch部分也不能分开;
接下来,我们来思考一个问题:当我们采用try{} finally{}组合时,程序如何来处理异常呢?是的,我们没有提供catch{}代码段,那么在异常发生以后,我们没有处理,这个异常怎么样了?答案是,这个异常被转给了该方法的调用者。应该了解的一个常识是,在执行过程方法调用的时候,计算机实际上会做一个保护调用环境,并将其压栈的工作,然后才转到被调用的过程和方法的入口开始执行;执行完毕,将栈中保存的环境进行恢复,回到调用者调用该方法的语句,继续执行。为什么要说这个呢,因为我们的问题和这个背景知识有密切的关系:异常被转移了。这个机制被成为:异常传递机制。如果调用者也不处理,那么异常就继续沿调用顺序继续被传递,直至到达main()函数,如果main()还是不处理,那只能由JVM站出来了,最后的结果就是屏幕上出现一些错误信息:告诉用户,应用发生了异常,是从哪里开始发生的,等等……,我现在没有办法继续工作了。(谁让你们都不处理的?)
Java的异常捕获顺序
Java的Exception 有很多种类,在Java1.4的api document中,列出的就有:
Direct Known Subclasses:
AclNotFoundException, ActivationException, AlreadyBoundException, ApplicationException, AWTException, BackingStoreException, BadLocationException, CertificateException, ClassNotFoundException, CloneNotSupportedException, DataFormatException, DestroyFailedException, ExpandVetoException, FontFormatException, GeneralSecurityException, GSSException, IllegalAccessException, InstantiationException, InterruptedException, IntrospectionException, InvalidMidiDataException, InvalidPreferencesFormatException, InvocationTargetException, IOException, LastOwnerException, LineUnavailableException, MidiUnavailableException, MimeTypeParseException, NamingException, NoninvertibleTransformException, NoSuchFieldException, NoSuchMethodException, NotBoundException, NotOwnerException, ParseException, ParserConfigurationException, PrinterException, PrintException, PrivilegedActionException, PropertyVetoException, RefreshFailedException, RemarshalException, RuntimeException, SAXException, ServerNotActiveException, SQLException, TooManyListenersException, TransformerException, UnsupportedAudioFileException, UnsupportedCallbackException, UnsupportedFlavorException, UnsupportedLookAndFeelException, URISyntaxException, UserException, XAException
很多吧。在我们的程序中,有两个不可能是我们要知道的:
我们的程序不可能处理所有的异常;
我们的程序也不可能产生所有的异常;
我们只关心也只可能关心其中一部分我们感兴趣的种类。
前面我们也提到了,一个try{} 代码段可以有多个catch{},那么我们怎么安排这多个catch{}呢?原则:先特殊,再一般。就是说,先处理子类异常,再处理父类异常。可能不太好理解,举个例子:
public class ReadFile
{
public static void main()
{
try
{
//some statement which concerning about reading files.
}
catch(FileNotFoundException e)
{
System.err.println(“File not fond.”);
System.err.println(e.getMessage());
e.printStackTrace();
}
catch(IOException e)
{
System.err.println(“I/O error.”);
System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
为什么把处理FileNotFoundException的部分放在IOException 前面?还记得前面说的原则吗?在有多个catch段的情况下,先子类后父类。从api document中我们可以找到这样的描述:
Class FileNotFoundException
看到了吗?FileNotFoundException是从IOException继承来的。这下明白了吧。
如果我们把这个顺序反过来会怎么样呢?你可以自己试试看。
结果是什么?Java编译器报错了:……Exception has already been caught.
抛出和处理的博弈:
我们的程序中,我们出了要处理异常,也会抛出异常。Java规定,如果我们自己的方法需要抛出异常,我们就有责任来告诉编译器,这就是抛出异常声明,除非,要抛出的异常是RunimeException的子类。
对这个问题的详细解释是:
1 Java中的异常分为两种:一种是检查异常,一种是非检查异常。非检查异常指RuntimeException 或者Error 及它们的子类。
2 检查异常需要被捕获和处理;非检查异常则不必。
3 Java要求每一个用Java语言来实现的方法,或者以catch{}代码段来捕获检查异常,或者在方法的声明语句中告诉编译器,自己要传递检查异常(把异常抛出),其格式是
public MethodName() throw **Exception
{
//statements
}
其中 **的意思是指定某一类的异常。
4 还有一种特殊情况,尽管我们提供了catch{}代码段来处理异常,但处理的方式是把异常继续抛出,那么我们就必须同时通知编译器,自己可能要把异常抛出。这是一个极端的例子。
总结下来,就是说,对于检查异常,我们要不自己处理,要不就声明自己可能抛出异常,否则,编译报错。是不是象捕获处理和抛出的博弈呢?
反思Java编译器的抱怨
Java编译器为设么会这么设计?这和Java的设计逻辑有关。根据它的设计思想,使程序正常工作使开发人员的责任。为了达到这一个目的,Java某种程度上强制用户去关心错误的处理(捕获,处理异常),这样,异常处理的部分就成为程序的一个组成部分了,这也从很大程度上帮助增强了Java程序的稳定性和健壮性。
但是,我们看到这样的程序了吗:
try
{
//some statement
}
catch(Exception e) {}
什么感想?人类真“伟大”,这真是“上有政策,下有对策” 在Java语言中的典型体现啊!不错,编译通过了,可这和编译器被设计有这样要求的初衷却相去遥远了。我们聪明的欺骗了可怜的智能有限的编译器,我们自己呢?除了一时的方便之外,我们得到什么了呢?
说明:从这部分开始,我同时参考了另外一本Java 教材:《Java2学习指南》,以丰富笔记的内容,并通过对比的方式,从不同的角度来更好的理解知识点。
我个人的感觉,这是一本很不错的教程,内容组织合理全面,基本覆盖到了java 语言的各主要内容,翻译也很好,语句通顺,表意明了。推荐各位有空阅读。
书籍信息:
Java2学习指南 (美)贝茨等著 袁鹏飞等译 人民邮电出版社 2004.01出版 ISBN 7-115-11803-5
English Name: Sun Certified Programmer Developer for Java2 Bates. B.
相关文章:
读书笔记:《Java2 教程》(一)