需要异常机制的原因:
-
必须在运行期间解决一些问题
-
简化错误控制代码
作用:让错误的缔结者(运算表达式或函数等)通过一些办法向接收者(调用者)传递一些适当的信息,使其知道该如何正确地处理遇到的问题。
基本代码格式:
-
try { 需要被检测的代码 } catch(异常类变量) { 处理异常的代码;(处理方式) }
-
try { 需要被检测的代码 } catch(异常类变量) { 处理异常的代码;(处理方式) } finally { 一定会执行的语句 }
-
try { 需要被检测的代码 } finally { 一定会执行的语句 }
Throwable(所有异常的父类)中常用三种函数:
-
getMessage():返回异常的详细信息
-
toString():返回异常类的简短描述
-
printStackTrace():打印这个Throwable及向后追踪信息
相关关键词
-
throws
用于函数上声明可能抛出的异常类
-
throw
函数中用于抛出异常类对象
-
try
用于避免函数在其内部因为抛出异常而退出,可以在函数内部设置一个特殊的代码块,用它捕获异常,这个特殊的代码块叫作“try块”。]try块属于一种普通的作用域,用一个try关键字开头:
try{
//可能产生异常的代码
}
-
catch
程序中产生的异常必须在异常控制模块中止,而且针对想捕获的每种异常,都必须有一个相应的异常控制模块。异常控制模块紧接在try块后面,并用catch关键字标记,如下所示:
try{ <span style="white-space:pre"> </span>//可能产生异常的代码 } catch(Type1id1){ <span style="white-space:pre"> </span>//处理Type1型的异常 } catch(Type2id2){ <span style="white-space:pre"> </span>//处理Type2型的异常 } catch(Type3id3){ <span style="white-space:pre"> </span>//处理Type3型的异常 } //etc ……
-
finally
用于存放函数在无论工作正常或发生异常情况下都必须执行的语句。(执行到System.exit(0)除外)多用于清除(已设置外部事物的状态)、关闭(打开的数据库连接或打开的文件)等操作。
注意:在采用finally的一种特殊配置下,可能会造成一种异常丢失。
比如:
//:LostMessage.java //How an exception can be lost class VeryImportantException extends Exception { <span style="white-space:pre"> </span>publicString toString() { <span style="white-space:pre"> </span>return"A very important exception!"; <span style="white-space:pre"> </span>} } class HoHumException extends Exception { <span style="white-space:pre"> </span>publicString toString() { <span style="white-space:pre"> </span>return"A trivial exception"; <span style="white-space:pre"> </span>} } public class LostMessage { <span style="white-space:pre"> </span>void f() throws VeryImportantException { <span style="white-space:pre"> </span>throw new VeryImportantException(); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>void dispose() throws HoHumException { <span style="white-space:pre"> </span>throw new HoHumException(); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>publicstatic void main(String[] args) throws Exception { <span style="white-space:pre"> </span>LostMessagelm = new LostMessage(); <span style="white-space:pre"> </span>try{ <span style="white-space:pre"> </span>lm.f(); <span style="white-space:pre"> </span>}finally { <span style="white-space:pre"> </span>lm.dispose(); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>} }///:~
输出如下:
Atrivial exception
atLostMessage.dispose(LostMessage.java:21)
atLostMessage.main(LostMessage.java:29)
可以看到,这里不存在VeryImportantException(非常重要的违例)的迹象,它只是简单地被finally从句中的HoHumException代替了。这是一项相当严重的缺陷,因为它意味着一个违例可能完全丢失。而且就象前例演示的那样,这种丢失显得非常“自然”,很难被人查出蛛丝马迹。而与此相反,C++里如果第二个违例在第一个违例得到控制前产生,就会被当作一个严重的编程错误处理。
异常种类
-
Error:代表编译期和系统错误,我们一般不必特意捕获它们(除在特殊情况以外)。
-
Exception:是可以从任何标准Java库的类方法中“掷”出的基本类型。此外,它们亦可从我们自己的方法以及运行期偶发事件中“掷”出。
-
特殊子类:RuntimeException
-
可以不在函数上声明RuntimeException及其子类
这是因为RuntimeException这个类别中的异常类对象都是由Java自动生成,
无需在程序中,把它们作为检查Exception的一部分。如果程序中出现
RuntimeException类别的异常,它们本身可以指出编程中的错误,用于之后的程序修改。
在自己编写的程序中,可以只是有选择的抛出一部分RuntimeException
类别的异常,这样可以避免代码变得繁复。
-
-
-
自定义异常类
必须继承某一异常类可以是Error或Exception以及它们的子类,这是因为throw和throws的操作对象是Throwable类及其子类
如果自定义异常类定义的异常发生后会影响程序的运行,可以继承RuntimeException,
用于指出错误,引导程序员修改调用程序。
-
构造
在自定义异常类的构造函数中,将异常信息传递通过super(“异常信息”)传给父异常类
这样可以通过getMessage()方法获取异常信息
classSelfDefineException { <span style="white-space:pre"> </span>SelfDefineException(){} <span style="white-space:pre"> </span>SelfDefineException(Stringmsg){ <span style="white-space:pre"> </span>super(msg); //将异常信息传给父类异常 <span style="white-space:pre"> </span>} }
-
使用
调用程序只能通过throw手动抛出自定义异常类
-
异常的使用
-
调用者对被调用者异常声明的处理方式
-
捕获:使用catch块
-
声明:使用throws,以便异常向上抛出
-
-
异常建立和处理原则(包括多异常处理)
-
在定义的函数中声明异常时,最好声明更为具体异常,以便处理方式可以更具体
-
异常缔造者(函数内或函数上)声明几个异常,异常处理者就对应有几个catch块,不要定义多余的catch块
多catch块顺序:如果多个catch块中的异常出现继承关系,父类异常catch块位于子类异常之后
-
使用catch处理时,应该在catch中定义具体实用的处理方式,而非简单避过捕获的异常
处理方式可以是创建异常日志文件
-
对于运行时异常--RuntimeException及其子类,程序中不做处理也能通过编译
-
异常应用注意事项
-
一般情况下,函数内出现异常,函数上需要声明
-
当函数内throw的异常类是RuntimeException或其子类,函数上可无需声明
-
在函数覆盖时,覆盖函数只能抛出被覆盖函数声明的异常及其子类,也可以劣势或者不抛
子类继承父类时,可能存在声明异常函数的覆盖问题。
使用异常的好处
-
将问题进行封装
-
将正常流程代码和问题处理代码分离,方便阅读
资料来源:
2.Java编程思想第四版完整中文-第9章
3.Java手册