Bootstrap

Java基础(8)异常

目录

1.前言

2.正文

2.1异常的引入

2.2异常的类型

2.2.1编译时异常

2.2.2运行时异常

2.3区分Exception与Error

2.4异常的声明,抛出与捕获

2.4.1throw

2.4.2throws

2.4.2try-catch与finally

2.6自定义异常

3.小结


1.前言

哈喽大家好啊,Java基础马上就要到尾声了,讲完异常这个章节之后再讲一个String类,Java基础基本就结束了,那么让我们废话不多说开始下面的学习。

2.正文

2.1异常的引入

异常是什么,虽然这个概念听起来很陌生,但在我们平时编写程序的时候肯定会出现异常啦,下面就是据一些例子:

public class test {
    public static void main(String[] args) {
        System.out.println(10 / 0);
    }
}

 接下来就让我们来解释一下这个异常:

它表示在算术运算过程中出现了异常情况。这个异常通常在执行算术运算时抛出。

public class test {
    public static void main(String[] args) {
        int[] array = new int[] {1,2,3,4,5};
        System.out.println(array[10]);
    }
}

这个也是一个常见的异常,大概意思如下:

它表明程序试图访问数组中不存在的索引。换句话说,当你尝试访问数组的某个元素时,如果使用的索引超出了数组的有效索引范围(即小于0或大于等于数组长度),就会抛出这个异常。 

我们见识了这些常见的异常,那么异常到底是什么呢,接下来就是异常的概念:

异常(Exception)是指程序执行过程中可能出现的不正常情况或错误。它是一个事件,会中断正在执行的程序,并可能导致程序出现错误或崩溃。

2.2异常的类型

2.2.1编译时异常

编译性异常(也称为编译时异常或检查型异常)是在编译阶段就能被检测到的异常,它们必须被显式地捕获或声明在方法签名中,至于如何写在方法签名中下文的throws会讲解。另外要注意以下几点:

  • 编译时异常必须在编译时处理,要么通过try-catch语句捕获处理,要么通过方法签名使用throws关键字声明抛出。如果既没有捕获也没有声明抛出,编译器会报错。
  • 受检异常通常表示可恢复的错误,也就是说,程序在遇到这类异常时,可以选择恰当的恢复策略,比如重新尝试操作、提供替代方案等。

2.2.2运行时异常

运行时异常表示在程序运行时可能发生的错误。这些异常通常是程序逻辑错误导致的,编译器不会强制要求开发者捕获这些异常。运行时异常的主要特点如下:

  • 运行时异常在编译时不需要处理,编译器不会强制要求捕获或声明抛出。这意味着,即使代码中存在可能抛出运行时异常的情况,编译器也不会报错。

  • 运行时异常通常表示不可恢复的错误,一旦发生,程序往往无法继续正常执行。因此,运行时异常通常不需要捕获处理,而是通过代码审查和测试来避免。

2.3区分Exception与Error

在区分这个之前,我们需要先讲解一下异常的本质:

异常在Java中的本质是类。Java的异常处理机制是建立在类和对象的基础上的。所有的异常都是从java.lang.Throwable类派生出来的子类。Throwable类有两个重要的子类:ExceptionError

在明白这个之后我们就可以来区分Exception与Error了,Exception表示程序运行时可预料的异常,可以被捕获(即通过try-catch处理)并处理,使程序有机会恢复;而Error表示JVM或系统层面的严重错误,通常不可预料且无法恢复,不建议捕获处理。

2.4异常的声明,抛出与捕获

在我们明白异常的概念之后,那我们在实际的编程中要如何处理这些异常,如何尽可能规避这些异常呢,接下来我们就需要来讲解几个关键字以及具体应用

2.4.1throw

throw的语法规则如下:

throw new Exception("自定义异常信息");

有以下几个需要注意的点:

  • 抛出的异常必须是Throwable类的子类。
  • throw关键字只能在方法内部使用,不能在方法外部或静态代码块中直接抛出异常。

下面是具体的示例: 

public class test {
    // 一个方法,用于检查输入的数字是否为正数
    public void checkPositiveNumber(int number) {
        // 使用throw关键字抛出一个IllegalArgumentException
        if (number <= 0) {
            throw new IllegalArgumentException("数字必须是正数");
        }
        System.out.println("数字是正数: " + number);
    }

    public static void main(String[] args) {
        test example = new test();
        example.checkPositiveNumber(10);
        example.checkPositiveNumber(-1);
    }
}

主函数中分别输入了10和-1,运行结果如下:

2.4.2throws

throws关键字是用于声明下段代码可能会出现异常,并标示出来,实际上并没有起到解决异常根本的作用,为了使程序能够进行下去,接下来是具体的使用规则:

public void someMethod() throws ExceptionA, ExceptionB {
    // 方法体
}

使用时有以下注意的点:

  • 只能声明检查型异常throws只能用于声明检查型异常(其中的大类是编译型异常),不能用于非检查型异常。
  • 可以声明多个异常:一个方法可以声明它可能会抛出多个异常类型。
  • 方法内部不处理的异常:如果一个方法可能会抛出某些异常,但选择不处理它们,那么必须在方法签名中使用throws声明这些异常。
  • 构造函数和静态初始化块throws不能用于构造函数和静态初始化块。

下面就对上文出现的代码中的异常进行了声明: 

public class test {
    // 一个方法,用于检查输入的数字是否为正数
    public void checkPositiveNumber(int number) throw IllegalArgumentException{
        if (number <= 0) {
            throw new IllegalArgumentException("数字必须是正数");
        }
        System.out.println("数字是正数: " + number);
    }

    public static void main(String[] args) {
        test example = new test();
        example.checkPositiveNumber(10);
        example.checkPositiveNumber(-1);
    }
}

2.4.2try-catch与finally

try-catch是Java中用于异常处理的一组关键字,它们允许程序在发生异常时捕获并处理这些异常,而不是让程序崩溃,具体语法规则如下:

try {
    // 可能抛出异常的代码
} catch (ExceptionType name) {
    // 异常处理代码
}

一般在代码进行完后,我们需要对代码运行做一些收尾工作,比如将之前Scanner关闭等,语法规则如下:

try {
    // 可能抛出异常的代码
} catch (ExceptionType name) {
    // 异常处理代码
} finally {
    // 总是执行的代码,常用于清理工作
}

我们拿以下代码做示例:

import java.util.Scanner;

public class test {

    public int add(int a, int b) throws IllegalArgumentException {
        if (a < 0 || b < 0) {
            throw new IllegalArgumentException("数字不能为负数");
        }
        return a + b;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        test calculator = new test();
        try {
            System.out.print("请输入第一个加数:");
            int num1 = scanner.nextInt();
            System.out.print("请输入第二个加数:");
            int num2 = scanner.nextInt();

            int result = calculator.add(num1, num2);
            System.out.println("两数之和为:" + result);
        } catch (IllegalArgumentException e) {
            // 捕获并处理IllegalArgumentException
            System.out.println("错误:" + e.getMessage());
        } finally {
            // 关闭scanner资源
            scanner.close();
            System.out.println("finally已运行.....");
        }
    }
}

这一段代码实现的功能很基础,但运用了我们上文所讲的所有的关键字,接下来详细分析一下该代码的俩种执行结果:

如果俩数皆为正数:

  • 则在运行完try模块后直接运行finally板块。

 


如果俩数中有负数:

  • 在跳转到add方法时抛出IllegalArgumentException异常
  • catch对该异常进行捕捉并打印错误信息(对异常进行实例化然后调用getMessage自带的方法)
  • 再运行finally。

2.6自定义异常

Java中已经为我们提供了许多异常,但我们在实际工程中也可以自己创建一个更加切合应用场景的自定义异常,来更好的为项目服务,提供更加详尽的异常信息。接下来我们以一个登陆系统背景为例来讲清楚,示例如下:

class passWordException extends Exception {
    public passWordException() {
        super();
    }

    public passWordException(String s) {
        super(s);
    }
}

class Login {
    private static String correctPassword = "123456";
    private String password;

    public Login(String password) {
        this.password = password;
    }

    public boolean checkPassword() throws passWordException {
        if (!this.password.equals(correctPassword)) {
            throw new passWordException("密码错误!");
        }
        return true;
    }
}

public class test {
    public static void main(String[] args) {
        try {
            Login login1 = new Login("123456");
            System.out.println("尝试登录1: " + login1.checkPassword());

            Login login2 = new Login("654321");
            System.out.println("尝试登录2: " + login2.checkPassword());
        } catch (passWordException e) {
            System.out.println("捕获到异常: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

上段代码展示了如何自定义一个异常类,在继承Exception类后在自定义异常类中写自己的方法, 最后进行调试。

运行结果如下:

第一次登陆时没有异常,第二次登陆后触发该异常,捕捉到异常后打印异常信息(红字中均是打印出的错误信息)

3.小结

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,加油!

;