Java基础入门(七)---异常处理

一、异常的基本概念

(一)异常的定义与分类

  1. 核心定义:异常是Java程序运行时出现的非正常情况(如除0、数组索引越界),会中断程序正常流程,Java通过异常类封装这些情况并提供处理机制。
  2. 继承体系:所有异常的父类是Throwable,其下分为两类:
    • Error类:系统级错误(如资源耗尽),程序无法恢复,无需处理。
    • Exception类:程序级异常,可通过代码处理,是异常处理的核心。
  3. 编程案例(认识异常):
java 复制代码
public class ExceptionDemo {
    // 两数相除方法
    public static int divide(int x, int y) {
        return x / y; // 可能出现除0异常
    }

    public static void main(String[] args) {
        int result = divide(4, 0); // 除数为0,触发异常
        System.out.println(result); // 异常后代码无法执行
    }
}
  1. 案例注意事项:
    • 上述代码运行时会抛出ArithmeticException(算术异常),程序直接中断,后续打印语句无法执行。
    • 异常未处理时,JVM会自动打印异常信息(类名、原因、堆栈轨迹)并终止程序。
  2. 逻辑思维培养:
    • 养成"预判异常"思维:编写代码时思考可能出现的非正常情况(如参数为0、数组为空),提前规划处理方案。
    • 理解"异常分层":区分ErrorException,聚焦Exception的处理,避免无效编码。

二、运行时异常与编译时异常

(一)两类异常的定义与区别

  1. 运行时异常(unchecked异常):
    • 定义:RuntimeException类及其子类(如NullPointerExceptionIndexOutOfBoundsException),编译时不强制处理,运行时触发。
    • 特点:多由逻辑错误导致(如数组索引越界),可通过优化代码避免。
  2. 编译时异常(checked异常):
    • 定义:Exception类中非RuntimeException的子类(如IOException),编译时必须处理(捕获或声明抛出),否则无法通过编译。
  3. 编程案例(运行时异常):
java 复制代码
public class RuntimeExceptionDemo {
    public static void main(String[] args) {
        int[] arr = new int[5];
        System.out.println(arr[6]); // 数组索引越界异常(运行时异常)
    }
}
  1. 案例注意事项:
    • 上述代码编译时无报错,但运行时抛出ArrayIndexOutOfBoundsException,属于运行时异常。
    • 编译时异常(如文件操作相关的IOException)必须显式处理,否则编译器直接报错。
  2. 逻辑思维培养:
    • 区分"可避免异常"与"必须处理异常":运行时异常通过规范逻辑(如先判断索引范围)避免,编译时异常需提前规划处理流程。
    • 养成"先校验后执行"习惯:访问数组前判断索引范围,调用方法前校验参数合法性,减少运行时异常。

三、异常处理语法

(一)try...catch语句

  1. 核心作用:捕获并处理异常,使程序在异常后仍能继续执行。
  2. 语法格式:
java 复制代码
try {
    // 可能触发异常的代码
} catch (异常类型 e) {
    // 异常处理逻辑
}
  1. 编程案例:
java 复制代码
public class TryCatchDemo {
    public static int divide(int x, int y) {
        return x / y;
    }

    public static void main(String[] args) {
        try {
            int result = divide(4, 0); // 可能触发异常的代码
            System.out.println(result); // 异常后此句不执行
        } catch (ArithmeticException e) {
            // 处理异常:打印异常信息
            System.out.println("异常原因:" + e.getMessage());
        }
        System.out.println("程序继续执行..."); // 异常处理后正常执行
    }
}
  1. 案例注意事项:
    • try块中异常发生后,后续代码立即终止,直接进入匹配的catch块。
    • 多个catch块捕获不同异常时,子类异常需放在父类异常前面(如ArithmeticException在前,Exception在后)。
  2. 逻辑思维培养:
    • 养成"精准捕获"思维:明确try块可能触发的异常类型,避免直接捕获Exception(不利于定位问题)。
    • 设计"异常处理逻辑":根据场景选择处理方式(如打印日志、返回默认值、提示用户),而非仅打印异常信息。

(二)finally语句

  1. 核心作用:无论是否发生异常,finally块中的代码都会执行,常用于释放资源(如关闭文件、数据库连接)。
  2. 语法格式:
java 复制代码
try {
    // 可能触发异常的代码
} catch (异常类型 e) {
    // 异常处理逻辑
} finally {
    // 必须执行的代码(如资源释放)
}
  1. 编程案例:
java 复制代码
public class FinallyDemo {
    public static int divide(int x, int y) {
        return x / y;
    }

    public static void main(String[] args) {
        try {
            int result = divide(4, 0);
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("异常原因:" + e.getMessage());
            return; // 提前结束方法
        } finally {
            System.out.println("finally块执行:释放资源"); // 仍会执行
        }
    }
}
  1. 案例注意事项:
    • 即使catch块中有returnbreak等语句,finally块依然执行(除非调用System.exit(0)终止JVM)。
    • finally块中避免使用return,否则会覆盖trycatch块的返回值。
  2. 逻辑思维培养:
    • 建立"资源闭环"思维:打开的资源(文件、网络连接)必须在finally中释放,避免资源泄露。
    • 区分"必须执行"与"可选执行":将清理工作放入finally,核心业务逻辑放入try,异常处理放入catch,结构清晰。

四、抛出异常

(一)throws关键字

  1. 核心作用:声明方法可能抛出的异常,将异常处理责任交给调用者(调用者需捕获或继续声明)。
  2. 语法格式:修饰符 返回值类型 方法名(参数) throws 异常类1, 异常类2... { 方法体 }
  3. 编程案例:
java 复制代码
public class ThrowsDemo {
    // 声明方法可能抛出ArithmeticException
    public static int divide(int x, int y) throws ArithmeticException {
        return x / y;
    }

    public static void main(String[] args) {
        try {
            int result = divide(4, 0); // 调用声明异常的方法,必须处理
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("处理异常:" + e.getMessage());
        }
    }
}
  1. 案例注意事项:
    • 方法声明的异常需是实际可能抛出的异常,避免冗余声明。
    • 调用声明编译时异常的方法,必须通过try...catch捕获或throws继续声明,否则编译报错。
  2. 逻辑思维培养:
    • 养成"责任传递"思维:方法内部无法处理的异常,通过throws交给调用者,明确异常处理边界。
    • 避免"盲目声明":仅声明方法确实可能抛出的异常,减少调用者的处理负担。

(二)throw关键字

  1. 核心作用:在方法体内主动抛出异常实例,常用于触发自定义业务异常(如参数非法)。
  2. 语法格式:throw new 异常类(异常信息);
  3. 编程案例:
java 复制代码
public class ThrowDemo {
    // 校验年龄合法性,非法则主动抛出异常
    public static void printAge(int age) throws Exception {
        if (age <= 0 || age > 120) {
            // 主动抛出异常,携带自定义信息
            throw new Exception("年龄非法:" + age + ",必须在1-120之间");
        }
        System.out.println("年龄:" + age);
    }

    public static void main(String[] args) {
        try {
            printAge(-5); // 触发主动抛出的异常
        } catch (Exception e) {
            System.out.println("捕获异常:" + e.getMessage());
        }
    }
}
  1. 案例注意事项:
    • throw抛出编译时异常时,方法需通过throws声明该异常;抛出运行时异常则无需声明。
    • throw语句后需立即终止代码(如return),否则后续代码无法执行。
  2. 逻辑思维培养:
    • 建立"主动校验"思维:业务逻辑中主动校验参数、状态合法性,通过throw提前触发异常,避免后续错误。
    • 设计"异常信息":抛出异常时携带明确信息(如"年龄非法:-5"),便于定位问题。

五、自定义异常

(一)自定义异常的定义与使用

  1. 核心定义:Java提供的异常类无法满足业务需求时,自定义异常类(需继承Exception或其子类)。
  2. 实现步骤:
    • 继承Exception类(编译时异常)或RuntimeException类(运行时异常)。
    • 提供无参和带异常信息的构造方法,调用父类构造。
  3. 编程案例:
java 复制代码
// 自定义异常类:除数为负数异常(编译时异常)
class DivideByMinusException extends Exception {
    // 无参构造
    public DivideByMinusException() {
        super();
    }

    // 带异常信息的构造
    public DivideByMinusException(String message) {
        super(message);
    }
}

public class CustomExceptionDemo {
    // 两数相除,除数为负数则抛出自定义异常
    public static int divide(int x, int y) throws DivideByMinusException {
        if (y < 0) {
            throw new DivideByMinusException("除数为负数:" + y);
        }
        return x / y;
    }

    public static void main(String[] args) {
        try {
            int result = divide(4, -2);
            System.out.println(result);
        } catch (DivideByMinusException e) {
            System.out.println("处理自定义异常:" + e.getMessage());
        }
    }
}
  1. 案例注意事项:
    • 自定义编译时异常(继承Exception)需显式处理(捕获或声明);自定义运行时异常(继承RuntimeException)则无需。
    • 自定义异常类名需见名知义(如DivideByMinusException),便于理解异常含义。
  2. 逻辑思维培养:
    • 养成"业务异常抽象"思维:将特定业务场景的异常(如"余额不足""参数非法")抽象为自定义异常,使代码更具可读性。
    • 区分"通用异常"与"业务异常":通用异常(如除0)使用Java自带类,业务特有异常(如除数为负)使用自定义类,边界清晰。
相关推荐
偷星星的贼112 小时前
如何为开源Python项目做贡献?
jvm·数据库·python
遇见你的雩风2 小时前
Java---多线程(一)
java·开发语言
二十雨辰2 小时前
[python]-基础语法
python
小白学大数据2 小时前
基于 Python 的知网文献批量采集与可视化分析
开发语言·爬虫·python·小程序
Ulyanov2 小时前
PyVista战场可视化实战(一):构建3D战场环境的基础
开发语言·python·3d·tkinter·gui开发
这就是佬们吗2 小时前
力扣---leetcode48
java·笔记·后端·算法·leetcode·idea
冗量2 小时前
Cucumber: 参考
java·bdd·cucumber
fai厅的秃头姐!2 小时前
01-python基础-day01python基础
python
冗量2 小时前
Cucumber:参数类型与配置详解
java·bdd·cucumber