异常处理(Java)

异常(Exception)

异常的概念

一个小例子来引出异常

public static void main(String[] args)  {
    int num1 = 10;
    int num2 = 0;//Scanner();
    try {
        int res = num1 / num2;
    } catch (Exception e) {
        e.printStackTrace();
    }

    System.out.println("程序继续运行....");

}

代码解读:

  1. num1 / num2 => 10 / 0
  2. 当执行到 num1 / num2 因为 num2 = 0, 程序就会出现(抛出)异常 ArithmeticException
  3. 当抛出异常后,程序就退出,崩溃了 , 下面的代码就不在执行
  4. 大家想想这样的程序好吗? 不好,不应该出现了一个不算致命的问题,就导致整个系统崩溃
  5. java 设计者,提供了一个叫 异常处理机制来解决该问题,如果程序员,认为一段代码可能出现异常/问题,可以使用 try-catch 异常处理机制来解决,从而保证程序的健壮性
  6. 将该代码块->选中->快捷键 ctrl + alt + t -> 选中 try-catch
  7. 如果进行异常处理,那么即使出现了异常,程序可以继续执行

代码运行效果:

image-20221110192135797

如果感觉红色太“喜庆”,可以将上述代码的第 7 行改为:

System.out.println("出现异常的原因=" + e.getMessage());//输出异常信息

代码运行结果:

image-20221110192217066

基本概念

Java 语言中,将程序执行中发生的不正常情况称为“异常”

**注意:**开发过程中的语法错误和逻辑错误不是异常

执行过程中所发生的异常事件可分为两大类

  1. Error(错误),Java 虚拟机无法解决的严重问题。如 JVM 系统内部错误、资源耗尽等严重情况。比如 StackOverflowError[栈溢出]和 OOM(out of memeory,内存不足),Error 是严重错误,程序会崩溃
  2. Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:空指针访问、读取不存在的文件、网络连接中断等等,Exception 分为两大类:运行时异常【程序运行时,发生的异常】和编译时异常【编程时,编译器检查出的异常】。

上面的小例子就是运行时异常

异常体系图🚩

异常中我们主要研究 Exception,Exception 中主要研究运行时异常(Runtime Exception)

image-20221110200712196 image-20221110195551999

image-20221110195916730

image-20221110195820963

异常体系图小结

  1. 异常分为两大类,运行时异常和编译时异常
  2. 运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免出现的错误。java.lang.RuntimeException 类及它的子类都是运行时异常。
  3. 对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
  4. 编译时异常是编译器必须处置的异常。(意思就是平时在写代码时,写的错误代码,编译器在代码下有红色波浪线,你不解决,编译器就不编译。)

常见的异常

常见的运行时异常

  1. NullPointerException 空指针异常
  2. ArithmeticException 数学运算异常
  3. ArrayIndexOutOfBoundsException 数组下标越界异常
  4. ClassCastException 类型转换异常
  5. NumberFormatException 数字格式不正确异常
NullPointerException 空指针异常

当应用程序试图在需要对象的地方使用 null 时,抛出该异常。也就是说这个对象你还没有创建起来你就去使用它,就会抛出空指针异常。

String name = null;
System.out.println(name.length());

报错信息:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
ArithmeticException 数学运算异常

当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时

int num1 = 10;
int num2 = 0;//Scanner();
int res = num1 / num2;

报错信息:

Exception in thread "main" java.lang.ArithmeticException: / by zero
ArrayIndexOutOfBoundsException 数组下标越界异常

用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引

int[] arr = {1,2,4};
for (int i = 0; i <= arr.length; i++) {
	System.out.println(arr[i]);
}

arr.length = 3,arr[3] ,下标 3 越界

报错信息:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
ClassCastException 类型转换异常

当试图将对象强制转换为不是实例的子类时,抛出该异常

public class test1 {

	public static void main(String[] args) {
		A b = new B(); //向上转型
		B b2 = (B)b;//向下转型,这里是 OK
		C c2 = (C)b;//这里抛出 ClassCastException
        }
	}
class A {}
class B extends A {}
class C extends A {}

报错信息:

Exception in thread "main" java.lang.ClassCastException: class test.B cannot be cast to class test.C
NumberFormatException 数字格式不正确异常

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 => 使用异常我们 可以确保输入是满足条件数字

String name = "bestpig";
//将 String 转成 int
int num = Integer.parseInt(name);//抛出 NumberFormatException
System.out.println(num);

报错信息:

Exception in thread "main" java.lang.NumberFormatException: For input string: "bestpig"

常见的编译异常

编译异常是指在编译期间就必须处理的异常,否则代码不能通过编译

  1. SQLException // 操作数据库时,查询表可能发生的异常
  2. IOException // 操作文件时发生的异常
  3. FileNotFoundException //当操作一个不存在的文件时发生的异常
  4. ClassNotFoundException // 加载类,而该类不存在时发生的异常
  5. EOFException // 操作文件,到文件末尾,发生的异常
  6. IllegalArguementException // 参数异常

举一个 FileNotFoundException 的例子:

FileInputStream fis;
fis = new FileInputStream("d:\\aa.jpg");
int len;
while ((len = fis.read()) != -1) {
    System.out.println(len);
}
fis.close();

写完之后,在 new FileInputStream("d:\\aa.jpg"),下会有红色波浪线,鼠标放上去显示报错信息

Unhandled exception type FileNotFoundException

异常处理🚩

基本介绍

异常处理就是当异常发生时,对异常处理的方式

异常处理的方式

  1. try - catch - finally

​ 程序员在代码中捕获发生的异常,自行处理

  1. throws

​ 将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是 JVM

示意图

image-20221111095852321

image-20221111095905251

说明:

f2 方法抛出异常,抛给 f1方法,f1可以通过 try - catch - finally 处理,也可以抛给 main 方法……。

**注意:**try -catch 和 throws 二选一

try - catch 异常处理

基本介绍
  1. Java 提供 try 和 catch 块来处理异常。try 块用于包含可能出错的代码。catch 块用于处理 try 块中发生的异常。可以根据需要在程序中有多个 try- catch 块。

  2. 基本语法

    try{
        // 可疑代码
        // 将异常生成对应的异常对象,传递给 catch 块
    }catch(异常){
        // 对异常的处理
    }
    // 如果没有 finally,语法可以通过
    
    
注意事项
  1. 如果异常发生了,则异常发生后面的代码不会执行,直接进入到 catch 块

    try {
        String str = "bestpig";
        int a = Integer.parseInt(str);
        System.out.println("数字:" + a);
    } catch (NumberFormatException e) {
        System.out.println("异常信息=" + e.getMessage());
    }
    
    System.out.println("程序继续...");
    

    运行结果:

    异常信息=For input string: "bestpig"
    程序继续...
    

    可见第 4 行代码并没有输出

  2. 如果异常没有发生,则顺序执行 try 的代码块,不会进入到 catch

    try {
        String str = "123";
        int a = Integer.parseInt(str);
        System.out.println("数字:" + a);
    } catch (NumberFormatException e) {
        System.out.println("异常信息=" + e.getMessage());
    }
    
    System.out.println("程序继续...");
    

    运行结果:

    数字:123
    程序继续...
    

    可见第 6 行代码并没有输出

  3. 如果希望不管是否发生异常,都执行某段代码(比如关闭连接,释放资源等)则使用如下代码- finally

    try {
        String str = "123";
        int a = Integer.parseInt(str);
        System.out.println("数字:" + a);
    } catch (NumberFormatException e) {
        System.out.println("异常信息=" + e.getMessage());
    }finally{
        System.out.println("finally 代码块被执行……");
    }
    System.out.println("程序继续...");
    

    运行结果:

    数字:123
    finally 代码块被执行……
    程序继续...
    
    try {
        String str = "bestpig";
        int a = Integer.parseInt(str);
        System.out.println("数字:" + a);
    } catch (NumberFormatException e) {
        System.out.println("异常信息=" + e.getMessage());
    }finally{
        System.out.println("finally 代码块被执行……");
    }
    
    System.out.println("程序继续...");
    

    运行结果:

    异常信息=For input string: "bestpig"
    finally 代码块被执行……
    程序继续...
    

    可见 第 8 行 都有被执行

  4. 可以有多个 catch 语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception 在后, NullPointerException 在前),如果发生异常,只会匹配一个 catch

    public class test1 {
    
        public static void main(String[] args) {
            try {
                Person person = new Person();
                person = null;
                System.out.println(person.getName());//NullPointerException
                int n1 = 10;
                int n2 = 0;
                int res = n1 / n2;//ArithmeticException
            } catch (NullPointerException e) {
                System.out.println("空指针异常=" + e.getMessage());
    
            } catch (ArithmeticException e) {
                System.out.println("算术异常=" + e.getMessage());
            } catch (Exception e) {
                System.out.println(e.getMessage());
            } finally {
    
            }
        }
    
    }
    
    class Person {
        private String name = "jack";
        public String getName() {
            return name;
        }
    }
    

    运行结果:

    空指针异常=Cannot invoke "test.Person.getName()" because "person" is null
    

    如果将第 6 行注释掉,则会捕获 ArithmeticException 异常

    jack
    算术异常=/ by zero
    
    1. 可以进行 try - finally 配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉/退出。应用场景:就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
执行顺序小结
  1. 如果没有出现异常,则执行 try 块中所有的语句,不执行 catch 块中语句,如果有 finally,最后还需要执行 fianlly 里面的语句
  2. 入股出现异常,则 try 块中异常发生后, try 块剩下的语句不再执行。将执行 catch 块中的语句,如果有 finally,最后还需要执行 fianlly 里面的语句

throws 异常处理

基本介绍
  1. 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
  2. 在方法声明中用 throws 语句可以声明抛出异常的列表,throws 后面的异常类型可以是方法中产生的异常类型,也可以是它的父类

快速入门案例

public void f2() throws FileNotFoundException {
    //创建了一个文件流对象
    //这里的异常是一个FileNotFoundException 编译异常
    //使用throws ,抛出异常, 让调用f2方法的调用者(方法)处理
    FileInputStream fis = new FileInputStream("d://aa.txt");
}

throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类

public void f2() throws Exception {
    FileInputStream fis = new FileInputStream("d://aa.txt");
}

throws 关键字后也可以是 异常列表, 即可以抛出多个异常

public void f2() throws FileNotFoundException,NullPointerException,ArithmeticException {
    FileInputStream fis = new FileInputStream("d://aa.txt");
}
注意事项和使用细节
  1. 对于编译异常,程序中必须处理,比如 try - catch 或者 throws
  2. 对于运行时异常,程序中如果没有处理,默认就是 throws 的方式处理

​ 这一个就是说你代码出错了,你没有写异常处理的方法,最终抛给了 JVM 来处理,JVM 就是直接打出错误信息。通俗点说就是平时写代码出错,控制台给出报错信息

  1. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的子类型
class Father { //父类
    public void method() throws RuntimeException {
    }
}

class Son extends Father {//子类
    //子类重写父类的方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型
    @Override
    public void method() throws ArithmeticException {
    }
}
  1. 在 throws 过程中,如果有方法 try - catch,就相当于处理异常,就可以不必 throws

​ 这个在前面的示意图已经说过,就是 try - catch 和 throws 二选一

补充一点:

public static void f1() {
    f3(); // 抛出异常
}
public static void f3() throws FileNotFoundException {
    FileInputStream fis = new FileInputStream("d://aa.txt");
}

这里大家思考问题:调用f3() 报错
因为f3() 方法抛出的是一个编译异常, 即这时,就要 f1() 必须处理这个编译异常,在 f1() 中,要么 try-catch-finally ,或者继续throws 这个编译异常

public static void f4() {
    //老韩解读:
    //1. 在f4()中调用方法f5() 是OK
    //2. 原因是f5() 抛出的是运行异常
    //3. 而java中,并不要求程序员显示处理,因为有默认处理机制
    f5();
}
public static void f5() throws ArithmeticException {

}

在 f4() 中调用方法 f5() 是不会报错的,原因是f5() 抛出的是运行异常,而java中,并不要求程序员显示处理,因为有默认处理机制(即默认向上抛出),就是相当于将第一行代码看为

public static void f4() throws ArithmeticException

只是 throws ArithmeticException不用我们去写,java 默认处理了。

自定义异常

基本概念

当程序中出现了某些“错误”,但该错误信息并没有在 Throwable 子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息

自定义异常的步骤

  1. 定义类:自定义异常类名(程序员自己写)继承 Exception 或 RuntimeException
  2. 如果继承 Exception,属于编译异常
  3. 如果继承 RuntimeException,属于运行异常

强烈建议:继承 RuntimeException

public class CustomException {
    public static void main(String[] args) /*throws AgeException*/ {
        int age = 180;
        //要求范围在 18 – 120 之间,否则抛出一个自定义异常
        if(!(age >= 18 && age <= 120)) {
        	//这里我们可以通过构造器,设置信息
            throw new AgeException("年龄需要在 18~120 之间");
        }
        System.out.println("你的年龄范围正确.");
    }
}

class AgeException extends RuntimeException {
    public AgeException(String message) {//构造器
    	super(message);
    }
}

throw 和 throws 的对比

意义位置后面跟的东西
throws异常处理的一种方式方法声明处异常类型
throw手动生成异常对象的关键字方法体中异常对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值