Java 异常 捕获与处理的详细介绍

一、异常简述

1.异常的三种类型

  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

2.异常的层次结构

Throwable 类是 Java 语言中所有错误(Error)或异常(Exception)的超类。

  • Error:程序所发生的的错误,无法处理,是能避免。
  • Exception:主要有 IOException 类和 RuntimeException 类两个子类。

在这里插入图片描述

3.了解异常处理

错误:只能通过修改源代码解决

//OutOfMemoryError: Java heap space 内存溢出错误
int arr[] = new int[1024*1024*1024];

异常:可以进行特定的处理,使程序继续运行

1.使用 throw 关键字处理
2.使用 throws 关键字,在方法声明时抛出异常
3.使用 try catch finally 关键字,捕获抛出异常

二、异常的处理

1.Java异常处理过程

1.JVM遇到异常会创建异常对象(对象内容包括:内容、原因、位置)
2.寻找 try catch 或者方法的 throws 异常抛出,如果没有异常抛出,则直接交给JVM进行处理
3.JVM根据接收到的异常信息在控制台进行打印,如果没有异常抛出,则终止程序

一个简单的异常程序举例
在这里插入图片描述

2.异常的处理

throw关键字

作用

抛出异常

格式

throw new xxxException("异常产生的原因")

代码实例

//定义一个空数组
int[] arr = null;
//判断数组是否为空
if(arr == null){
    
    
	//如果 if 判断成立,则使用 throw 关键字抛出异常
    throw new NullPointerException("数组传递过来为空");
}
//定义一个长度为 5 的数组
int[] arr = new int[5];
//设置 arr 数组的一个索引值
int index = 5;
//判断数组索引是否越界
if(index < 0 || index > arr.length - 1 ){
    
    
	//如果 if 判断成立,则使用 throw 关键字抛出异常
    throw new ArrayIndexOutOfBoundsException("数组索引越界了");
}

注意事项

1.throw关键字必须写在方法的内部
2.throw关键字后边new的对象必须是Exception或者Exception子类对象
3.throw关键字抛出指定异常对象,我们必须处理这个异常对象

  • 如果创建的是RuntimeException或者是RuntimeException的子类对象,可以默认不处理,交给JVM(打印异常,终止程序)
  • 如果创建的是编译异常(写代码时报错),必须处理这个异常

throws关键字

作用

方法内部抛出异常对象的时候,是必须处理这个异常对象的。
可以使用throws关键字处理异常对象,会把异常对象声明抛出给方法的调用者处理(自己不处理,给别人处理),最终交给JVM处理 → 中断处理。

格式

修饰符 返回值类型 方法名(参数列表) throws xxxExcepiton, yyyExcepiton, ...{
    
    
    throw new xxxExcepiton("xxx异常产生原因");
    throw new yyyExcepiton("yyy异常产生原因");
    ...
}

代码实例

public void test() throws /*FileNotFoundException*/ IOException{
    
    
	/*
    FileNotFoundException extends IOException
    如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
    */

    //定义一个目标文件路径
    String file = "c:\\exception.txt";
    
    //传递 c:\error.txt 与目标文件路径比较
    if(!file.equals("c:\\error.txt")) {
    
    
        throw new FileNotFoundException("文件路径不是c:\\exception.txt");
    }
    
    //传递 c:\exception.doc 与目标文件路径比较
    if(!file.endsWith("c:\\exception.doc")){
    
    
        throw new IOException("文件的后缀名不是.txt");
    }
}

注意事项

1.throws关键字必须写在方法声明处
2.throws关键字后边声明的异常必须是Exception或者是Exception的子类
3.方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常

  • 如果抛出的多个异常对象有子父类关系那么直接声明父类异常即可

4.调用了一个声明抛出异常的方法,必须的处理声明的异常

  • 要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM
  • 要么try…catch处理异常

try catch finally关键字

try:捕获异常。
catch:处理异常。
finally:不论是否发生异常,都会执行 finally块 的内容。

作用

方法内部抛出异常对象的时候,是必须处理这个异常对象的。
可以使用 try catch 关键字捕获、处理异常对象,由程序员根据情况处理。

格式
catch 块的数量是由 try 语句捕获的异常数量决定的,大多数情况只有一个 catch块。
finally 块可有可无

try{
    
    
    可能产生异常的代码
}catch(异常类名 变量名){
    
    
    异常的处理逻辑,异常异常对象之后,怎么处理异常对象
    一般在工作中,会把异常的信息记录到一个日志中
}
...
catch(异常类名 变量名){
    
    
	...
}finally{
    
    
    无论是否出现异常都会执行
}

代码实例

public class DemoTryCatchFinally {
    
    
    public static void main(String[] args) {
    
    
        //定义一个目标文件路径
        String file = "c:\\exception.txt";
        
        try {
    
    
            //传递 c:\error.txt 与目标文件路径比较
            if(!file.equals("c:\\error.txt")) {
    
    
                throw new FileNotFoundException("文件路径不是c:\\exception.txt");
            }
        } catch (IOException e) {
    
    
            //异常的处理逻辑
            //方法一
            System.out.println(e.getMessage());
            //方法二
			System.out.println(e.toString());
			//方法三(最常用)
            e.printStackTrace();
        } finally {
    
    
            //无论是否出现异常,都会执行
            System.out.println("资源被释放了");
        }
    }
}

在异常类的超类 Throwable 类中,定义了三个异常处理的方法,使用时根据需要选择合适的即可。

String getMessage()      返回此 throwable 的简短描述。
String toString()        返回此 throwable 的详细消息字符串。
void printStackTrace()   JVM打印异常对象,默认此方法,打印的异常信息是最全面的。

多个异常的处理

  1. 多个异常分别处理
    每一个异常使用一对 try catch
    
  2. 多个异常一次捕获,多次处理
    使用一个 try 多个 catch
    
  3. 多个异常一次捕获,一次处理
    使用一个 try 一个 catch
    

注意事项

1.try 中是否产生异常

  • 如果try中产生了异常,那么就会执行catch中的异常处理逻辑,执行完毕catch中的处理逻辑,继续执行try…catch之后的代码
  • 如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try…catch之后的代码

2.finally不能单独使用,必须和try一起使用
3.finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要资源释放(IO)
4.如果try和finally同时存在 return 语句,那么try的返回值会被finally中的返回值替换掉

三、自定义的异常

Java 提供的异常类,不能够满足所有的实际需要,需要自己定义一些异常类。
格式

public class xxxException extends Exception | RuntimeException{
    
    
     添加一个空参数的构造方法
     添加一个带异常信息的构造方法
}

代码实例
定义 自定义异常类

public class DemoException extends Exception{
    
    

    //添加一个空参数的构造方法
    public DemoException(){
    
    
        super();
    }

    /*
    添加一个带异常信息的构造方法
    查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息
    */
    public DemoException(String massage){
    
    
        super(massage);
    }
    
}

使用 自定义异常类

public class DemoExceptionTest {
    
    


    public static void main(String[] args) throws DemoException {
    
    
        test01();
        test02();
    }

    //使用 throws 关键字抛出异常
    private static void test01() throws DemoException {
    
    
        throw new DemoException("自定义异常");
    }

    //使用 try catch 捕获并抛出异常
    private static void test02() {
    
    
        try {
    
    
            throw new DemoException("自定义异常");
        } catch (DemoException e) {
    
    
            e.printStackTrace();
        }
    }
}

注意事项

1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2.自定义异常类,必须的继承Exception或者RuntimeException

  • 继承 Exception类:那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try…catch…
  • 继承RuntimeException类:那么自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)

猜你喜欢

转载自blog.csdn.net/weixin_44580492/article/details/107915498