前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java的”异常“超详细讲解

Java的”异常“超详细讲解

作者头像
黎鹤舞
发布2024-03-19 15:21:13
940
发布2024-03-19 15:21:13
举报
文章被收录于专栏:黎鹤舞的编程技术栏

Java的”异常“超详细讲解

前言:

​ 我们在写代码的时候,经常会遇到错误,并且编译器会给出相关提示 如:

这里就会显示 ArrayIndexOutOfBoundsException *(数组越界)*错误。并且会提示报错的行号。

同时我们发现 ArrayIndexOutOfBoundsException 是可以点击进去的,点击进去之后会发现是一个JDK自带的类

由此我们可以知道:

在Java中,不同类型的异常,都有与其对应的类来进行描述,也可以说异常也是一种类

但是我们在日常编写项目时,错误是时常发生的。我们作为程序员当然不希望一个项目时不时的崩溃。

在此之前,我们通常对代码可能出现的潜在问题用 条件判断来进行处理:,下面我以一个简略的游戏进行演示:

可以看到当条件一旦增加,代码就会非常臃肿,并且难以后续对功能进行增加和修改。

所以我们必须要学会如何使用,以及处理异常的方式!!

一、异常的分类:

  1. Throwable: 是异常体系的顶层类,其派生出两个重要的子类, ErrorException
  2. Error: **指的是Java虚拟机无法解决的严重问题,**比如:JVM的内部错误、资源耗尽等, 典型代表:StackOverflowError(栈溢出错误)和OutOfMemoryError
  3. Exception: 异常产生后程序员可以通过代码进行处理,使程序继续执行。而异常又分为运行时异常和编译时异常;
    1. 编译时异常: 编译无法通过,编译器会进行提醒。也称为受检查异常(Checked Exception)
    2. 运行时异常: 可以通过编译,但是运行后会报错。也称为非受检查异常(Unchecked Exception) 常见的 NullPointerException(空指针异常)、ArrayIndexOutOfBoundsException(数组越界异常)都属于运行时异常。

二、异常的处理:

1.异常的抛出:

在编写程序时,如果程序中出现错误,此时就需要将错误的信息告知给调用者

关键字:throw 语法:throw new 异常类型(要告知的信息);

代码案例:

代码语言:javascript
复制
public static void func(int[] arrays) {
    //如果传递的是一个空数组,抛出异常
    if(arrays == null) {
        //这里的NullPointerException是Java自带的一个类
        throw new NullPointerException("你传递了一个空指针");
    }
}
public static void main(String[] args) {
    int[] arrays = null;
    func(arrays);
}

运行结果:

注意事项

  1. 异常抛出 必须写在方法内部!!!(由方法来实现抛出)
  2. 抛出对象必须是Exception或是其子类
  3. 默认情况下:RuntimeException及其子类可以通过JVM处理
  4. 异常一旦抛出,其后的代码就不会执行

我们可以看到,在IDEA中,如果异常后还有代码,会直接提示编译错误(因为无法被执行!)

2. 异常声明:

关键字: throws 语法格式: 修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2…{ }

如果我们在使用方法是,有编译时异常(编译器警告),可以使用throws来声明这个异常可能会存在,这样就可以通过编译时异常了。

下面我以clone方法为例子:如果不对main函数进行异常声明,会提示clone编译错误(无法确定能否被克隆)

我们在main函数(使用者)后加入声明:throws CloneNotSupportedException

发现编译错误消失,可以正常运行:

代码语言:javascript
复制
class Student implements Cloneable{
    public String name;
    public int age;

    //构造方法:
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class CloneTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        Student s1 = new Student("张三",18);
        Student s2 = (Student) s1.clone();
    }
}

注意事项

  1. throws必须跟在方法的参数列表之后
  2. 声明的异常必须是 Exception 或者 Exception 的子类
  3. 方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型 具有父子关系,直接声明父类即可。
  4. 调用声明抛出异常的方法时,调用者必须对该异常进行处理,或者继续使用throws抛出

3.异常捕捉:

关键字:try - catch 语法格式: ​ try{ ​ // 将可能出现异常的代码放在这里 ​ }catch(要捕获的异常类型 e){ ​ //异常处理内容 ​ }[catch(异常类型 e){ ​ // 对异常进行处理 ​ }finally{ ​ // 此处代码一定会被执行到 ​ }]

解释:

  1. try { }: 内部放的是可能出现异常的代码块(也有可能没有异常) 如果出现异常,则异常后续的代码均不会被执行,直接跳转到对应异常类的的catch内容
  2. catch( ){ }
    1. ()小括号内是异常类类名 + 实例化的对象名(这里通常习惯用e表示)
    2. { } 花括号内表示的对应的异常处理内容
    3. 可以存在多个catch
    4. 也可以一个catch内写多个异常类型,只需要一个实例化对象名,中间用 | 隔开

    (不推荐用此写法,无法判断异常类型!!)

  3. finally{ } finally{}内的代码块,无论异常发生与否,始终会被执行 通常被用于资源的关闭,对资源进行回收。

注意事项:

  1. try块内抛出异常位置之后的代码将不会被执行
  2. 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到 JVM收到后中断程序----异常是按照类型来捕获的
  3. try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获
  4. 如果异常存在父子类关系,则必须子类在前(catch),父类在后(catch) 因为如果父类在前,子类内容无法被执行,肯定会被父类捕获(catch)

这里就是因为父类 RuntimeException在前,后续的InputMismatchException无法被执行,出现编译错误。 子类在前则只会抛出子类的异常,而不会抛出父类的异常。

  1. finally中的代码一定会执行的,且是最后执行。一般在finally中进行一些资源清理的扫尾工作
代码语言:javascript
复制
   public static int func3() {
       Scanner scanner = new Scanner(System.in);
       try{
           int a = scanner.nextInt();
           return a;
       } catch (InputMismatchException e) {
           //InputMismatchException是错误输入类型异常
           // (这里我想要输入的是int,但是输入String就会报此错误)
           e.printStackTrace();
           System.out.println("发生了InputMismatchException异常");
   
       }finally {
           scanner.close();
           System.out.println("Scanner资源已经关闭!!!");
           return 100;
       }
   
   }
   
   public static void main(String[] args) {
   
       int ret = func3();
       System.out.println(ret);
   }

注意这里,try语句中已经有了return 语句了, 正常情况下输出的结果是你输入的数;

我们进行输入测试:

我们会发现最终return的值是100,即为finally return的值,

这说明:finally不仅一定会执行,而且可以在return之后最后执行。

三、自定义异常类:

既然异常是一个类,那我们肯定也能通过定义类,来定义一个自定义的异常类型

具体如何定义呢 ?,我们可以仿照已知的异常类,这里是NullPointerException为例子:

定义方法为

  1. 继承RuntimeException类(异常父类) 或者是 Exception类。
  2. 重写构造方法并调用父类的构造,用来传递发生错误的字段

下面我以一个简单的登录代码来进行演示:

首先是 登录功能类:

代码语言:javascript
复制
public class Login {

    //这里是字段:
    public String userName;
    public String passWord;

    //进行简单的逻辑判断
    public void login(String userName,String passWord) {

        //如果输入的信息不匹配该类的成员信息,抛出自定义异常!(这里只抛出,不解决)
        if(!this.userName.equals(userName)) {
            throw new UserNameException("账户名输入错误!!!");
        }
        if(!this.passWord.equals(passWord)) {
            throw new PassWordException("密码输入错误!!!");
        }
    }

    //构造函数

    public Login(String userName, String passWord) {
        this.userName = userName;
        this.passWord = passWord;
    }
}

自定义类

首先是用户名错误的异常类:

代码语言:javascript
复制
public class UserNameException extends RuntimeException {
    public UserNameException() {
        super();
    }

    public UserNameException(String userName) {
        super(userName);
    }
}

其次是密码错误类:

代码语言:javascript
复制
public class PassWordException extends RuntimeException{

    public PassWordException() {
    }

    public PassWordException(String message) {
        super(message);
    }
}

在主函数中实例化:

代码语言:javascript
复制
public class Main {

    public static void main(String[] args) {

        try {
            Login login = new Login("admin","123123");
            login.login("admin","123");
        }catch (UserNameException e) {
            //打印函数栈信息
            e.printStackTrace();
        }catch (PassWordException e) {
            //打印函数栈信息
            e.printStackTrace();
        }finally {
            System.out.println("finally被执行,程序继续...");
        }

    }
}

输出结果:显示了自定义的异常类型 PassWordException

四、 总结:

异常的处理流程:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-12-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java的”异常“超详细讲解
  • 前言:
  • 一、异常的分类:
  • 二、异常的处理:
    • 1.异常的抛出:
      • 2. 异常声明:
        • 3.异常捕捉:
        • 三、自定义异常类:
        • 四、 总结:
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档