第7章-第1节-Java中的异常处理

1、异常Exception概述:

1)、异常的概念:

现实生活中万物在发展和变化会出现各种各样不正常的现象。

例如:人的成长过程中会生病。 实际工作中,遇到的情况不可能是非常完美的。

比如:你写的某个模块,用户输入不一定符合 你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据 库的数据,数据可能是空的等。 我们的程序再跑着,内存或硬盘可能满了等等。 软件程序在运行过程中,非常可能遇到刚刚提到的这些异常问题,我们叫异常,英文是: Exception , 意思是例外。 这些,例外情况,或者叫异常,怎么让我们写的程序做出合理的处 理,安全的退出,而不至于程序崩溃。

2)、实际开发中异常的理解:

实际开发中,异常从面向对象的角度考虑也是一类事物,我们可以向上抽取为异常类。这个异常类可以对一些不正常的现象进行描述,并封装为对象。

2、异常体系:

JDK 中定义了很多异常类,这些类对应了各种各样可能出现的异常事件,所有异常对象都是 派生于 Throwable 类的一个实例。 如果内置的异常类不能够满足需要,还可以创建自己的异 常类。 Thorwable 类(表示可抛出)是所有异常和错误的超类,两个直接子类为 Error ( 错误)和 Exception ( 异常)。

先来看看 java 中异常的体系结构图解:

1)、Error类:

 Error是 java 所有错误类的父类,描述了 java 运行时系统内部错误和资源耗尽错误。这 类错误是我们无法控制的,同时也是非常罕见的错误,表明系统 JVM 已经处于不可恢复的崩 溃状态中,它是由 JVM 产生和抛出的,比如 OutOfMemoryError 、 ThreadDeath 等。 所以错误是很难处理的,一般与硬件及运行实际环境有关,一般来说程序员是无法处理这些错 误的,我们在编程中,可以不去处理这类错误 例如内存溢出,需要的内存超出了 java 虚拟机管理的内存范围

//递归模拟内存溢出
public class Test01 {
    public static void main(String[] args) {
        A(0);
    }
}
    
public static void A(int num){
    num += 1;
    A(num);
}

Error与Exception的区别:

Error错误,就好像我们开车去上班,结果半路车坏了,那么这种问题我们是没办法提前预知道的
Exception 就好像,我们开车去上班,我们广播中已经提示了A路线堵车,那么我们就可以换条路线即可。

2)、Exception类:

Exception 类所有异常类的父类,其子类对应了各种各样可能出现的异常事件。 Error 是程序无法处理的错误,但是 Exception 是程序本身可以处理的异常,在程序中应当尽可能去处理这些异常。

3)、运行时异常RuntimeException:

RuntimeException 和 他 的 所 有 子 类 异 常,都 属 于 运 行 时 期 异 常 。

例如: NullPointerException 、 ClassCastException 、 IndexOutOfBoundsException 、 ArithmeticException 等。 因为程序编译时异常不能被检查出,所以又称为 不检查异常 ( UnCheckedException ) 。 运行时异常一般是由程序逻辑错误引起的,所以在编写程序时,我们应该从逻辑角度尽可能避 免这类异常的发生。 当出现 RuntimeException 的时候,系统将自动检测并将它们交给缺省的异常处理程序(虚 拟 机 接 管 并 处 理 ) , 用 户 可 以 不 必 对 其 处 理 。

比 如 : 我 们 从 来 没 有 人 去 处 理 过 NullPointerException 异常,它就是运行时异常,并且这种异常还是最常见的异常之一。 ArithmeticException 异常,异常算术条件时抛出。 例如: “ 除以零 ” 的整数会抛出此类的一 个实例。

//空指针异常
public class Test01 {
    public static void main(String[] args) {
        int [] nums = null;
        System.out.println(nums.length);
    }
}

4)、编译时异常:

要求程序员在编写程序阶段必须预先对这些异常进行处理,如果不处理编译器报错,因此得名编译时异常

public class BianYiDemo {
    public static void main(String[] args) throws ParseException {
        String str = "2022-07-09";
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = format.parse(str);

        System.out.println(date);
    }
}

3、异常处理

1)、throws抛出异常:

public static void main(String[] args)throws ParseException{
    B(); //此处爆出红线
}

public static void B() throws ParseException{
    Date parse = new SimpleDateFormat("yyyy-MM-dd").parse("2024-01-05 00:00:00");
    System.out.println(parse);
}

throws 关键字表示,抛出异常,跟在方法后,后可跟多个异常,当前虽然可以抛出不处理,抛出异常的方法被调用处,还是要处理!

【注意】

throws虽然抛出异常,当前代码块中的红线消失可以运行,但是如果代码逻辑或者数据错误,还是会爆出异常,这是因为,throws是负责将异常向上抛出,谁调用此方法谁就负责处理这个异常,那么此处的main方法将异常继续向上抛出,那么main方法是JVM调用的,所以就相当于异常抛给了JVM,然而JVM没有处理这个异常,所以异常信息还是会打印出来!

2)、try-catch捕获异常:

public static void main(String[] args) {
    try {   // try块可能为出现异常的代码段
        B();
    } catch (ParseException e) {  // catch 块为捕获异常(要捕获的异常类型)
        //处理异常的方式
        System.err.println("您的时间格式错误!请修正!!");
    }
}
    
public static void B() throws ParseException {
    Date parse = new SimpleDateFormat("yyyy-MM-dd").parse("2024=01-05 00:00:00");
    System.out.println(parse);
}

try块表示发生异常的代码;

catch表示捕获异常,随后打印异常信息,也可以继续向上抛出!

3)、try-catch-finally:

try catch 后还可接finally块,而finally块中代码无论异常是否发生,都会执行!!常用于关闭资源等操作!

public static void main(String[] args) {
    try {
        C();
    } catch (ArithmeticException e) {
        System.err.println("分母为0了!!!!快去检查!!!!!");
    }finally {
        //常常用于关闭关键资源
        System.out.println("我是 finally 数据块!,如果出现异常,那就让我关闭数据库资源!");
    }
}

//定义一个方法  模拟分母为0的异常情况
public static void C() throws ArithmeticException {
    int num1 = 10;
    int num2 = 0;
    System.out.println("我正常打开了数据库资源!!!!");
    System.out.println(num1/num2);
    System.out.println("我正常关闭数据库资源!!!!");
}

【思考】

        1>、如果 异常没有抓住 或者 没有出现异常 的情况下,finally 还会执行嘛? 都会执行

        2>、如果 遇见return 关键字,那么finally 还会执行嘛? finally 不会收到return影响的!

【finally块不会被执行的情况】有4种特殊情况,finally块不会被执行:

        1>、finally语句块中发生了异常 (中断了)

        2>、前面的代码中执行了System.exit()退出程序

        3>、程序中所在的线程死亡

        4>、关闭CPU

 4)、try-finally:

不去处理异常,但是finally还是会执行

try {
    C();
} finally {
    //常常用于关闭关键资源
    System.out.println("我是 finally 数据块!我关闭数据库资源!");
}
//....

5)、getMessage和e.PrintStackTrace区别:

try {
    C();
} catch (ArithmeticException e) {
    System.err.println("分母为0了!!!!快去检查!!!!!");
    //System.out.println(e.getMessage());
    e.printStackTrace();
} finally {
    //常常用于关闭关键资源
    System.out.println("我是 finally 数据块!我关闭数据库资源!");
}
//.....

getMessage:获取异常简单的描述信息。

语法格式:String msg = exception.getMessage();

PrintStackTrace:打印异常追踪的堆栈信息,比较适合于程序的调试阶段

语法格式:exception.printStackTrace();

6)、throw关键字:

throw关键字为手动抛出异常

通过自己判断出现异常的地方,来手动throw抛出异常,因为是运行时异常,在调用处可以不去处理.

在后面的学习中,我们会慢慢发现,throw通常会提供一种方法的多样性,常常搭配if结构一起使用!

public static void main(String[] args) {
    try {
            C();
    } catch (Exception e) {
            System.out.println("分母为0!!!");
    }
}
    
//定义一个方法  模拟分母为0的异常情况
public static void C() {
    int num1 = 10;
    int num2 = 2;
    if(num2==0){
        throw new ArithmeticException("我是throw关键字 --->   分母为0啦!");
    } else {
        System.out.println(num1/num2);
    }
}

7)、throw和throws:

不同点:

1>、位置不同。throws用在方法上,后边跟的是异常类,可以跟多个异常类。throw用在方法内,后面跟的是异常对象

2>、功能不同,throws用来声明异常,让调用者只知道该功能可能出现的问题,throws表示出现异常的一种可能性,并不一定会发生这些异常;throw抛出具体的问题对象,执行throw则一定抛出了某种异常对象

 相同点:两者都是消极处理异常的方式

4、自定义异常:

1)、定义:继承Throwable或者他的子类Exception的用户自己定义的异常类。前面的内容提到的都是系统有的异常类。

2)、在程序中使用自定义异常的步骤:

  • 创建自定义异常类

  • 编写异常信息

  • 通过throw关键字使用自定义异常类

例如:

class AgeException extends Exception {
    public AgeException(String message) {
        super(message);
    }
}

public class Test03 {

    //用户输入年龄方法
    public static void input() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入姓名:");
        String name = scanner.next();//接收键盘上姓名的输入
        System.out.println("请输入年龄:");

        while (scanner.hasNext()) {
            //Scanner类中的hasNext()方法可以判断下一个输入是否为整数,整数才会进入到循环体,该程序利用这个特点并且结合if判断语句来控制年龄的输入是否<0
            try {
                int age = scanner.nextInt();//接收键盘上年龄的输入
                if (age < 0) {
                    throw new AgeException("年龄不能为负数");//2、一旦出现年龄输入为< 0的情况,就会通过throw抛出一个AgeException类的对象并且捕获处理
                }
                System.out.println("姓名" + name);
                System.out.println("年龄" + age);
                break;

            } catch (AgeException e) {
                System.out.println(e.getMessage() + "请重新输入:");
            }
        }
    }

    public static void main(String[] args) {
        input();
    }
}

5、final、finally、finalize的区别:

  • final用于声明属性,方法和类,分别表示属性不可交变,方法不可被重写,类不可继承。

  • finally是异常处理语句结构的一部分,表示总是执行。

  • finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。

本电子书目录:

《Java基础的重点知识点全集》

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zwarwolf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值