[Java基础篇]Java异常模块

前言

Java的基本理念是结构不佳的代码将不能运行。
异常(不期而至的各种状况)是程序中地一些错误,并不是所有的错误都是异常,但是有时候错误可以避免的。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。

一、Java中的异常层次结构

在这里插入图片描述
Error类(专门用来处理严重影响程序运行的错误,无法处理的错误,好比绝症): Java运行时系统的内部错误资源耗尽错误。应用程序不应该抛出这种类型的对象。如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力。
Exception(好比感冒、阑尾炎): 表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,必须要处理的。这种异常分为两大类:运行时异常和非运行时异常。
RuntimeException(运行异常): 由程序逻辑错误导致的异常。Java编译器不会检查它的,编译会通过。
非运行时异常(编译错误):RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法上说是必须进行处理的异常,否则,编译不通过。
非受查异常(继承于Error、RuntimeException类的所有异常): 即不检查异常,程序员也无需写异常处理的代码,自动捕获异常。
Throwable类中的常见方法:

public void printStackTrace(){///打印异常的详细信息
}///包含异常的类型、异常的原因、异常出现的位置,再开发和调试阶段,都得使用printStackTrace

public String getMessage(){///获取发生异常得原因
}///提示给用户得时候,就提示错误原因

public String toString(){///获取异常得类型和异常描述信息
}

二、常见的Exception类(运行时和非运行时)异常

在这里插入图片描述

三、异常的处理方式

在这里插入图片描述

3.1 抛出异常(throw)

在Java中,提供了一个throw关键字,且其用在方法内 ,它用来抛出一个指定得异常对象。
步骤: 创建一个异常对象;需要将这个异常对象告知给调用者。

格式: throw new 异常类名(参数)

public class Main {
    public static void main(String [] args){
        int [] arr = {1,3,2,4};
        int n = 4;
        int x = getElment(arr,n);
        System.out.println(x);
    }
    public static int getElment(int []arr,int n){
        if(n<0||n>arr.length-1){
            throw new ArrayIndexOutOfBoundsException("数组越界了");
        }
        int x = arr[n];
        return x;
    }
}

控制台输出结果(抛出异常)如下:
在这里插入图片描述

3.2 声明异常(throws)

声明异常: 将问题标识出来,报告给调用者。如果方法内抛出编译异常,而没有捕获处理,那么必须通过throws进行声明,让调用者去处理。
关键字throws 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)。通俗地,用在声明方法时,表示该方法可能要抛出异常。

public void Method() throws Exception1,...{///可以声明多个异常
 ....
}
3.3 throws和throw的区别
关键字 位置不同 作用不同 是否出现异常
throw 用在方法头(函数体) 表示抛出异常,由方法体内的语句处理,所以它是抛出一个异常实例 执行throw就是一定抛出了某种异常
throws 用在方法声明后面(函数头) 表示再抛出异常 ,使它的调用者知道要捕获这个异常 表示出现异常的一种可能性,并不一定会发生这些异常

共性: 都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

3.4 捕获异常(try…catch)

如果异常出现的话,会立刻终止程序,所以我们得处理异常。一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉
方法处理异常的两种情况:
1、该方法不处理,而是声明抛出,由该方法的调用者来处理
2、在方法中使用try-catch 的语句块来处理异常

try{///该代码块中编写可能产生异常的代码
...
}catch(异常类型 e){///用来进行某种异常的捕获,实现对捕获到的异常进行处理
  处理异常的代码
  //记录日志/打印日常信息/继续抛出异常
}

try…catch语句: 如果你在方法内部抛出了异常(或在方法内部调用的其他方法抛出了异常),这个方法将抛出异常的过程中结束。这是我们不希望的,所以try块内将可能发生异常的代码包起来,称为监控区域。Java方法在运行过程中出现异常,则创建异常对象(catch参数所定义的异常)。将异常抛出监控区域之外,由Java运行系统试图寻找匹配的catch子句以捕获异常(异常处理程序)。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。

注意:如果在try块的内部,不同的方法调用可能会产生类型相同的异常,你只需提供一个针对此类型的异常处理程序。

匹配的原则: 如果抛出的异常对象属于catch子句的异常类,或者属于该异常类的子类,则认为生成的异常对象与catch块捕获的异常类型相匹配。

3.5 finally代码块

有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally代码块中存放的代码都是一定被执行的。

try{
  //可能发生异常的程序代码
}catch(异常类型 e){
 //捕获并处理try抛出的异常类型
}finally{
 //无论异常是否发生,都将执行
}

try…catch…finally执行顺序:
资料来自于https://blog.csdn.net/hguisu/article/details/6155636?utm_source=app&from=singlemessage
1、当try没有捕获到异常时:
try语句块中的语句逐一被执行,程序跳过catch语句块,执行finally语句块和其后的语句。
在这里插入图片描述
2、当try捕获到异常时:
· catch语句块里没有处理此异常的情况:此异常将会抛给JVM处理,finally语句还是会被执行,但finally语句块后的语句不会被执行。
· catch语句块里出现处理此异常的情况:当执行某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块,最后执行其他语句。
在这里插入图片描述
什么时候的代码块必须最终执行?
当我们在try语句块中打开了一些物理资源(磁盘文件/网路连接/数据库连接等),我们都得在使用完后,最终关闭打开得资源。
finally块不会被执行的4种特殊情况:
1、在finally语句块发生异常。
2、前面代码使用了System.exit()退出程序。
3、程序所在的线程死亡
4、关闭CPU
finally的其他用法
当在try块或catch块中遇到return语句时,finally将在返回之前被执行:

public class Main {
    public static void main(String [] args){
       System.out.println(f(2));//输出0
    }
     public static int f(int x){
        try{
            int n = x*x;
            return n;
        }finally{
            if(x==2) return 0;
        }
     }
}

耦合try/catch和try/finally语句块

///如果finally子句中出现错误时,会报告finally子句中出现的错误。
InputStream in = ...;
try{///确保报告出现的错误

  try{///确保关闭输入流
  
  }finally{
   in.close();
  }
}catch(IOException e){
  ...
}
3.6 异常的注意事项

对于有多个catch子句的异常程序来说,应该尽量将捕或底层异常类的catch子句(如:子类)放在前面,同时尽量将捕获相对高层的异常类的catch子句如:父类)放在后面。否则,捕获底层异常类的catch子句将可能会被屏蔽。
多个异常使用捕获情况:
1、多个异常分别处理
2、多个异常一次捕获,多次处理
3、多个异常一次捕获一次处理。
一般我们是使用一次捕获多次处理的方式。

四、自定义异常

为什么需要自定义异常类:
上面所学的异常,我们会发现都是JDK内部定义好的,但是实际开发中也会出现很多异常,这些异常很可能在JDK中没有定义过的,例如年龄的负数问题,考试问题,负数问题,那么能不能自己定义异常呢?
什么时自定义异常类:在开发中根据自己的业务异常情况来定义异常类。

五、参考资料

1.https://www.cnblogs.com/xiohao/p/3547443.html
2.https://blog.csdn.net/hguisu/article/details/6155636?utm_source=app&from=singlemessage
3.黑马程序员

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章