Java中异常处理机制的理解与应用

本文详细介绍了Java中的异常处理机制,包括异常的分类、处理方式以及相关概念。异常分为编译时异常和运行时异常,处理方式包括异常声明、捕获和finally块。还探讨了如何自定义异常类型,并展示了异常对象的方法和构造器的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常

客观角度:不符合现实生活的各种情况,都可以理解为是异常

Java语言角度:在代码的运行过程中,出现的各种错误导致程序停止运行,那么这些错 误就是异常。

  • 注意:异常在程序种是通过一个个对象来表示

  • 和异常相关的类型:

    Throwable 该类型是所有异常类的父类

    Error:错误 一般表示比较严重的问题,一旦出现该问题,无法通过代码解决

    Exception:异常 一般表示比较轻微的问题,如果程序种出现异常,可以通过代码来处理或者解决该异常。

    编译时异常:除了运行时异常,其他类型都是编译时异常

    运行时异常:RunTimeException 类型以及 它的子类类型

在这里插入图片描述

编译型异常和运行时异常

  • 编译时异常:在代码编译阶段,系统会检查代码的语法格式等情况,如果在检查的过程中出现了问题,就提示一个错误,这些问题就属于编译时异常。

  • 运行时异常:在代码编译阶段不对代码进行检查,但是在代码运行阶段,如果出现了一些导致程序意外终止的问题,这些问题就属于运行时异常。

  • 注意: 不管是编译时异常还是运行时异常,都只会在运行阶段出错。

JAVA虚拟机默认处理异常的方式

  • 如果在代码中的某个方法内出现了错误情况,系统会将这个错误发生的原因,发生异常类型,发生的路径封装到异常对象中。
  • 如果当前方法中没有处理这个异常对象,就将异常往上抛出,抛给调用该方法的方法。
  • 如果调用的方法也没有处理异常,那么就一层一层往上抛出,直到抛给main方法,main方法再抛给虚拟机
  • 虚拟机将当前异常对象通过标准错误流,打印到控制台,并结束自己。

代码:

在这里插入图片描述

手动处理异常的方式

  • 异常声明
  • 异常捕获
异常声明

如果在某个方法中出现了编译时异常,可以在当前方法上声明这个异常的类型,声明之后编译时异常就会消失。

  • 声明异常的格式:
修饰符 返回值类型 方法名称 (参数列表)throws 异常类型1,异常类型2…{
        方法体语句;
    }
  • 注意事项:

    • 异常的声明,不能从本质上解决问题,只能在编译阶段不检查这段代码

      如果后续传入一些错误的数据,在运行阶段也可能会发生错误。

    • 如果方法1中进行了异常的声明,方法2调用了方法1,那么方法2需要对该异常进行捕获或者处理。

    • 在声明异常的时候,尽量声明小的异常类型

 public static void main(String[] args) throws ParseException{
        test();
    }
public static void test() throws ParseException {
        SimpleDateFormat sim = new SimpleDateFormat();
        Date date = sim.parse("2022年2月28号");
        System.out.println(date);
    }
异常的捕获

如果代码的某个位置会出现了错误情况,可以使用特定的格式,捕获这个 错误,捕获之后可以按照自己定义的方式去处理异常。

  • 格式:

    try … catch

    try … catch … finally

    try … finally

try … catch
try{
   可能会出现错误的代码
}catch(异常类型 异常对象名称){
   处理异常的方式
}
  • 执行流程:

    • 先执行try中的代码,检测是否出现异常
    • 如果try中的代码没有出现问题,trycatch直接结束,代码正常执行trycatch后面的代码。
    • 如果try中出现了异常,程序立即跳转到catch中查看出现异常所属的类型和catch中声明的类型是否一样,如果一样,就捕获该异常按照指定的方式去处理异常,处理之后,trycatch结束
    • 如果try中出现了catch中没有声明的异常类型,就不能捕获该异常,这时虚拟机来处理这个异常(默认处理方式)。
  • 注意事项:

    如果在某行代码中,出现了异常,立即去catch块中去匹配异常类型,出现错误的代码后面的代码就不能执行了。

代码:

public static void main(String[] args)  {
        Scanner sc =new Scanner(System.in);
        System.out.println("请输入日期");
        String s =sc.nextLine();
        SimpleDateFormat sim = new SimpleDateFormat("yyyy年MM月dd日");
        try {
            Date da = sim.parse(s);
            System.out.println(da);
        }catch (ParseException parseException){
            System.out.println("格式输入有问题!");
        }
    }
try … catch格式的多种异常情况
  • 格式:
try{
   可能出现错误的代码
}catch(异常类型1 对象名1){
    异常1的处理方式
}catch(异常类型2 对象名2){
   异常2的处理方式
}...
  • 流程:

    • 先执行try中的代码,检测是否出现异常
    • 如果出现了异常, 就先和异常类型1匹配,如果能匹配上就执行异常1的处理方 式,处理之后,直接结束整个try…catch语句,执行之外的代码。
    • 如果不能和异常类型1匹配,就继续和异常类型2匹配,如果能匹配上,就执行异常类型2的处理方式,之后结束整个try…catch语句,执行之外的代码。
    • 如果异常类型2不能匹配,依次类推,往后匹配。
    • 如果出现的异常,catch中的类型都不能匹配,虚拟机默认处理
  • 注意事项

    • 如果定义的多个catch块中的类型,有子父类的关系,不能将父类的类型定义在子类的类型前面。
    • 如果ctach块中定义的多个异常类型,要使用同一种处理方式,可以使用||来定义异常类型。

代码:

public static void main(String[] args) {
         try {
             int[] i = new int[5];
             System.out.println(i[4]);
             String s  ="20200412";
             SimpleDateFormat sim = new SimpleDateFormat();
             Date da = sim.parse(s);
             System.out.println(da);

         }catch (ArrayIndexOutOfBoundsException indexOut){
             System.out.println("索引越界");
         }catch (ParseException | NullPointerException Exception ){
             System.out.println("格式不匹配或者空指针异常");
         }
    }
try … catch…finally
  • 格式:

    try{
       可能会发生错误的代码
    }catch(异常类型1 异常对象1){
        异常1的处理方式
    }catch(异常类型2 异常对象2){
        异常2的处理方式
    …
    }finally{
       一定需要执行的代码
    }
    
  • finally 使用原因:

    • 如果有某些代码一定要执行,将代码放在try中或者catch中或者trycatch外都有可能执行不到
    • 将这段代码放在finally块中,不管遇到什么情况,系统都会去执行finally中的内容。
  • 注意:

    • finally关键字不能单独使用,一般是用来定义一个代码块
    • finally代码块也不能单独使用,一定是和try代码块一起使用
try … finally
  • 格式:

    try{
       第一段代码
    }finally{
       第二段代码
    }
    
  • 作用:

    如果在程序中,有多段代码,多段代码都需要有执行的机会,那么可以将这多段代码,分别放在try中和finally中,这样,多段代码之间就会互不影响,都有执行的机会。用来分隔代码,让代码之间互不影响,都有执行的机会。

代码:
在这里插入图片描述

异常类型中的方法

在异常的体系中,顶层父类Throwable中定义了一下操作异常对象方法

常用方法:

  • getMessage() :返回发生异常的原因

    getCause() :返回引起调用者异常对象发生的另一个异常对象

    toString() :返回该异常对象发生的原因及所属的类型

    printStackTrace() :返回该异常发生的路径,原因及类型

public static void main(String[] args) {
        try {
            int i = 10 / 0;
            System.out.println(i);
        } catch (ArithmeticException ae) {
            //返回异常发生的原因
            String str = ae.getMessage();
            System.out.println("该异常发生的原因:"+str);
            //返回引发该异常发生的异常对象
            System.out.println(ae.getCause());
            //打印除该异常的类型、原因、位置
            ae.printStackTrace();
            //返回异常的类型以及原因
            System.out.println(ae.toString());
        }
    }
/*
该异常发生的原因:/ by zero
null
java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
	at note.ExceptionMothed.main(ExceptionMothed.java:8)

*/

异常中的构造方法

  • Throwable() :创建一个没有任何属性值的异常对象
//学生类
public int getAge() {
        if (age<0){
            //创建一个有原因为异常对象
            RuntimeException exp = new RuntimeException();
            throw  exp;
        }
        return age;
    }
//测试类
 Student s = new Student();
        s.setAge(-1);
        try {
            System.out.println(s.getAge());
        }catch (RuntimeException exp){
            //获取异常出现的原因
            System.out.println(exp.getMessage());
            System.out.println("重新录入学生年龄:");
            s.setAge(new Scanner(System.in).nextInt());
        }
//null
//重新录入学生年龄:
  • Throwable(String message) :创建一个有原因的异常对象
//学生类
public int getAge() {
        if (age<0){
            //创建一个有原因为异常对象
            RuntimeException exp = new RuntimeException("年龄不能小于零");
            throw  exp;
        }
        return age;
    }
//测试类
 Student s = new Student();
        s.setAge(-1);
        try {
            System.out.println(s.getAge());
        }catch (RuntimeException exp){
            //获取异常出现的原因
            System.out.println(exp.getMessage());
            System.out.println("重新录入学生年龄:");
            s.setAge(new Scanner(System.in).nextInt());
        }
//年龄不能小于零
//重新录入学生年龄:

throw关键字

  • throw:抛出异常
  • 使用场景:如果在某个方法中出现了和正常生活不符合的情况,开发人员可以在该方法中创建一个异常对象,但是创建的异常对象自己不会自动抛出,需要使用throw关键字抛出异常。
  • 注意事项:
    • 在创建一个异常对象之后,一定要主动抛出,如果不抛出,该异常对象就不起作用。
    • 如果抛出的是一个运行时异常,在编译阶段不做检查,在运行阶段如果传入的数据是错误的,就会执行该异常。
    • 如果抛出的是一个编译时异常,在抛出之后,编译期间就会出现这个异常,可以声明也可以捕获处理。

throw和throws关键字的区别

  • throw关键字是用来抛出一个创建的异常对象

    throws关键字使用来声明一个异常类型

  • throw关键字在方法中使用

    throws关键字在方法的声明上(参数列表的后面)使用

  • throw一次只能抛出一个异常对象

    throws可以一次抛出多个异常类型(抛出的多个类型之间使用逗号分隔)

自定义异常类型

  • 使用原因:

    在异常的体系中官方定义了很多异常类型,但是大多类型都没有自己特殊的方法和属性,目的就是为了使用不同的类型来区分各种问题,当看到对应的类型时,就知道代码 中出现了什么问题,方便去开发者分析代码并解决问题。

  • 步骤:

    • 创建一个类型以Exception结尾

    • 将这个异常类型继承Exception或者RunTimeException

      如果继承了Exception类型,当前定义的类型就是一个编译时异常

      如果继承了RuntimeException类型,当前定义的类型就是一个运行时异常类型

    • 在该类中调用父类的构造方法,用于让子类创建对象

使用原因:

在异常的体系中官方定义了很多异常类型,但是大多类型都没有自己特殊的方法和属性,目的就是为了使用不同的类型来区分各种问题,当看到对应的类型时,就知道代码 中出现了什么问题,方便去开发者分析代码并解决问题。

  • 步骤:

    • 创建一个类型以Exception结尾

    • 将这个异常类型继承Exception或者RunTimeException

      如果继承了Exception类型,当前定义的类型就是一个编译时异常

      如果继承了RuntimeException类型,当前定义的类型就是一个运行时异常类型

    • 在该类中调用父类的构造方法,用于让子类创建对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

皮卡丘不断更

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

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

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

打赏作者

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

抵扣说明:

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

余额充值