java基础——异常机制
【捕获异常】硬件的错误、输入错误、物理限制等问题,都可能导致程序运行时的异常出现。
1.异常的分类层次
在java中,异常对象都是由Throwable类继承而来的,主要分为两大类:
Error和Exception类。
在Exception中又分为:
RuntimeException异常和非RuntimeException异常。
异常的分类有以下几种:
1.Error类层次的结构主要描述了java运行时系统的内部错误和资源耗尽等错误,如硬件错误、输入错误数据、系统崩溃等。出现这些系统内部的问题,除了通知用户并尽量安全退出,基本上程序员也无能为力了,所以这种情况一般不要求解决,当然,这种情况也很少出现。
2.RuntimeException的异常时指运行时异常,也称为未检查异常。一般是由于程序员自己的问题造成的,如错误的类型转换、数组访问越界、访问空指针等。这些都是可以通过程序员的细心处理和认真分析来避免的。如在转换类型时检查,通过检查下标来防止越界,使用变量前检查是否为空来杜绝空指针异常。
3.非RuntimeException异常,也就是已检查异常。常见的已检查异常主要有以下几种:java.io.IOEeception(IO异常,输入输出设备不存在,比如在文件的末尾读取数据)和java.io.FileNotFoundException(文件未找到异常)和java.lang.ClassNotFoundException(动态地装载某个类时,找不到此类)
注意:对于已检查异常必须处理,对于未检查异常可以处理也可以不处理
Java异常类层次结构图:

2.捕获和处理异常
语法规则:
- 返回类型方法名(参数)
- {
- try{
- 可能出现的异常语句A
- 可能出现的异常语句B
- 可能出现的异常语句C
- }
- catch(异常类e){
- //某种异常的引用
- 异常处理的语句D
- }
- finally{
- 最终一定会执行的语句E
- }
- 其他语句F
- }
finally语句块内的语句无论在什么时候在什么情况下都会被执行,经常会写一些释放资源的语句。如果前面语句中有一个return的值,finally中也有一个return的值,那么返回的一定是fianlly中return的值。
finally和catch可以省略其中的一个,但是不能同时省略
示例:
- publicclassExceptionTest{
- publicstaticvoidmain(String[]args){
- //写一个for循环和switch分支语句,一次运行会抛出异常的语句
- for(inti=0;i<5;i++){
- intj=0;
- try{
- System.out.PRintln("本条语句正常");
- //每次运行1条语句,前4条抛出异常,最后一条不抛出异常
- switch(i){
- case0:intzero=0;
- j=1/zero;break;
- case1:intb[]=null;
- j=b[0];break;
- case2:intc[]=newint[2];
- j=c[3];break;
- case3:charch="hello".charAt(9);break;
- case4:charcha="abc".charAt(1);break;
- }
- System.out.println("前面的语句都没有异常抛出才会运行我");
- }catch(Exceptione){
- System.out.println("第"+(i+1)+"次捕获异常");
- System.out.println("显示的异常信息为:"+e);
- }finally{
- System.out.println("无论前面怎样,这条语句都会执行");
- }
- }
- }
- }
上面代码中case的前四句话必定会抛出异常:
case:0是零做了除数;
case:1是数组没有赋值,也就是没有初始化就使用
case:2是数组越界
case: 3是字符串越界
结果:

3.异常的匹配
如果try语句后跟多个catch语句,那么排列的先后顺序如下所示:
1.如果多个catch语句块中所指定的异常类型级别相同或者没有任何派生关系,则catch语句排列无序。2.如果多个catch语句块中所指定的异常类型相互之间有派生关系,则必须子类型的异常写在上面,父类型的异常写在下面。
【自定义和抛出异常】1.自定义异常
当系统中已有的异常类型不能满足使用要求时,可以根据自己的需要抛出自定义异常的对象。自定义异常类一般通过充当捕获异常的角色,所以从Exception类或者其他的捕获异常类继承就可以了其语法格式如下:
- class类名extendsException{
- 类体;
- }
自定义的异常类一般都会编写必要的构造方法和一些适当的功能方法,而且一般都会有两个构造方法:
一个是无参的构造方法
一个是以字符串做参数的构造方法
以字符串做参数的构造方法可以在有出错信息的情况下创建异常对象。
示例:
- //自定义异常类ReportNotFoundException,有两个构造方法
- publicclassReportNotFoundExceptionextendsException{
- ReportNotFoundException(){
- }
- ReportNotFoundException(Stringmesg){
- super(mesg);//创建异常对象
- }
- }
2.抛出异常
在声明或者方法中抛出异常,主要内容和使用方法如下:在编程中会遇到很多异常,如果该程序有能力解决,可以用try/catch方法主动获取和处理异常。当不具备对异常进行处理的能力时,则向上抛出异常,直到抛到能够处理异常的位置。
抛出异常的语法是:
- 访问限制修饰符[static]方法名(参数列表)throws异常序列{
- 方法体;
- }
比如,有一个m方法抛出了IOException和InterruptedException。代码如下:
- publicvoidm()throwsIOException,InterruptedException{
- 方法体;
- }
throws用来声明该方法将有可能抛出的异常,将可能抛出的异常列在throws后面,用逗号隔开
在方法体中处理异常的时候,也可以将这两种捕获异常再抛出,使用throws语句就可以将一个异常对象抛出语法格式为:
当一个方法中出现异常,而没有处理,则以异常对象为返回值返回调用处,然后逐级传递。如果一直没有捕获和处理,最终异常将返回虚拟机,虚拟机终止退出,程序结束。
示例:
自定义异常:
- //自定义异常类ReportNotFoundException,有两个构造方法
- publicclassReportNotFoundExceptionextendsException{
- ReportNotFoundException(){
- }
- ReportNotFoundException(Stringmesg){
- super(mesg);//创建异常对象
- }
- }
职员及相应方法:
- publicclassEmployee{//定义公开的职员类型
- Stringname;
- publicEmployee(Stringname){
- this.name=name;
- }
- publicStringgetReport()throwsReportNotFoundException{
- //定义职员找报表的方法,找不到报表就报自定义异常
- if(Math.random()>0.7){//设定找到报表的几率是70%
- thrownewReportNotFoundException(name+"找不到报表");
- }
- returnname+",报表找到了";
- }
- }
- classManager{//定义经理类
- Employee[]es;//职员数组
- publicManager(Employee[]es){
- super();
- this.es=es;
- }
- publicStringgetReport()throwsReportNotFoundException{
- //定义经理找报表的方法
- StringBuffersb=newStringBuffer();//StringBuffer定义经常变化的字符串
- for(inti=0;i<es.length;i++){
- sb.append(es[i].getReport());//经理让所有职员找报表
- }
- returnsb.toString();
- }
- }
- classCFO{//定义CFO类
- Manager[]ms;
-