【Java】Java 异常处理机制详解

    大家好,最近整理了 Java 异常相关的知识点,今天系统和大家分享一下 Java 的异常处理机制。异常是开发中避不开的内容,合理处理异常能让程序更加健壮,避免无故崩溃。

    一、什么是异常

    简单来说,异常就是打断程序正常执行流程的意外事件。程序按照既定逻辑运行时,一旦出现异常,代码就会终止执行。如果不做任何处理,程序会直接闪退。

    而 Java 提供了完善的异常处理体系,我们可以主动捕获、处理异常,既保证核心业务继续运行,也能给用户友好的提示。

    二、Error 与 Exception 的区别

    Java 中所有异常和错误的顶层父类是Throwable,它主要分为两大分支:ErrorException

    1. Error(错误)属于系统级别的严重问题,通常是虚拟机、硬件层面引发的致命错误,代码层面无法捕获和处理。比如内存溢出、虚拟机崩溃等,一旦出现,程序基本无法恢复。示例:OutOfMemoryError(内存溢出错误)。
    2. Exception(异常)这是我们日常开发重点关注的部分,代表程序运行中出现的可修复问题,我们可以通过代码主动捕获、处理。比如除数为 0、空指针、文件不存在等。

    三、受检异常与运行时异常

    Exception又分为Checked 受检异常Unchecked 非受检异常(运行时异常)

    1. Checked 受检异常

    编译阶段就会被编译器检查,必须显式捕获或者向上抛出,否则代码直接编译报错。这类异常大多和外部资源交互有关,比如文件读写、网络请求。

    常见:IOExceptionClassNotFoundException

    2. Unchecked 运行时异常

    继承自RuntimeException,编译阶段不会报错,运行时才会触发。这类异常大多是代码书写不规范导致的,理论上可以通过提前判空、逻辑校验规避。

    常见:空指针、除数为零、数组下标越界等。

    代码示例:运行时异常(算术异常)

    public class ExceptionDemo {
        public static void main(String[] args) {
            int a = 10;
            int b = 0;
            // 除数为0,运行时抛出ArithmeticException
            int result = a / b;
            System.out.println(result);
        }
    }
    

    运行上述代码,程序会直接抛出算术异常并终止。

    四、throw 与 throws 关键字

    这两个关键字名字相近,但用法、位置、作用完全不同,是高频考点,也是开发常用语法。

    1. throws

    写在方法声明处,作用是声明当前方法有可能抛出的异常,把异常交给方法的调用者去处理。

    • 可以同时声明多个异常,用逗号分隔;
    • 主要用于处理受检异常。

    代码示例:throws 声明异常

    import java.io.FileReader;
    import java.io.IOException;
    
    public class ThrowsDemo {
        // 声明该方法可能抛出IOException受检异常
        public static void readFile() throws IOException {
            FileReader fr = new FileReader("test.txt");
            fr.close();
        }
    
        public static void main(String[] args) throws IOException {
            readFile();
        }
    }
    

    2. throw

    写在方法内部,作用是手动主动抛出一个异常对象

    • 一次只能抛出一个异常对象;
    • 一般结合条件判断使用,自定义异常场景使用较多。

    代码示例:throw 主动抛出异常

    public class ThrowDemo {
        public static void checkAge(int age) {
            if (age < 0) {
                // 手动抛出异常对象
                throw new IllegalArgumentException("年龄不能为负数!");
            }
            System.out.println("年龄校验通过");
        }
    
        public static void main(String[] args) {
            checkAge(-5);
        }
    }
    

    两者核心区别总结

    1. 位置:throws在方法签名后,throw在方法体内;
    2. 内容:throws后跟异常类名,throw后跟异常实例对象;
    3. 数量:throws可声明多个异常,throw每次仅抛出一个。

    什么时候用 throws,而非 try-catch?

    如果一个方法内多处可能抛出异常,逐个编写try-catch会让代码臃肿、可读性变差。此时可以用throws将异常向上传递,统一在调用方集中处理。

    五、try-catch-finally 异常捕获结构

    这是 Java 最核心的异常处理语法,用来捕获并处理异常

    1. try 块

    用来包裹可能出现异常的代码。如果代码正常执行,走完try块;一旦出现异常,立刻终止当前行后续代码,跳转到catch块。

    2. catch 块

    用来捕获try中抛出的异常,并编写处理逻辑。

    • 一个try可以搭配多个catch,捕获不同类型异常;
    • 多个 catch 必须遵循:子类异常在前,父类异常在后,否则编译报错。

    3. finally 块

    可选配置,无论 try 中是否出现异常,finally 代码一定会执行(特殊情况除外)。

    核心用途:释放资源,比如关闭文件流、数据库连接、网络连接等。

    finally 不会执行的特殊场景

    1. 代码进入死循环;
    2. 执行 System.exit(0) 终止 JVM。

    完整代码示例:try-catch-finally 综合使用

    public class TryCatchFinallyDemo {
        public static void main(String[] args) {
            int num1 = 20;
            int num2 = 0;
    
            try {
                System.out.println("开始执行运算");
                int res = num1 / num2;
                System.out.println("运算结果:" + res);
            } catch (ArithmeticException e) {
                // 捕获算术异常并处理
                System.out.println("异常捕获:除数不能为0!");
                e.printStackTrace();
            } finally {
                // 资源释放/收尾代码,必定执行
                System.out.println("执行finally代码块,完成收尾操作");
            }
            System.out.println("程序继续向下运行");
        }
    }
    

    多 catch 写法示例

    public class MultiCatchDemo {
        public static void main(String[] args) {
            String str = null;
            try {
                str.length();
            } catch (NullPointerException e) {
                System.out.println("捕获空指针异常");
            } catch (Exception e) {
                // 父类异常放最后
                System.out.println("捕获通用异常");
            }
        }
    }
    

    六、Java 异常处理最佳实践

    结合日常开发经验,分享几点实用的规范,让异常处理更专业:

    1. 优先捕获具体异常不要直接捕获顶层Exception,会掩盖真实错误,不利于问题排查。能精准捕获NullPointerExceptionIOException就不要用Exception
    2. 不随意捕获无法处理的异常如果当前业务逻辑没有能力修复该异常,不要强行catch,使用throws向上抛出,交由上层调用方处理。
    3. 资源释放交给 finallyIO 流、数据库连接等资源,务必在finally中关闭,防止资源泄漏。
    4. 生产环境使用日志记录异常线上项目不要只用e.printStackTrace()打印控制台,推荐使用日志框架(SLF4J、Logback 等)记录异常堆栈、上下文信息,方便线上排错。

    写在最后

    异常处理是 Java 基础中非常重要的一环,从基础的概念区分,到try-catch-finallythrow/throws的使用,都是日常编码、面试的高频内容。掌握好异常机制,才能写出稳定、健壮的 Java 程序。

    Tags:

    发表回复

    Your email address will not be published. Required fields are marked *.

    *
    *