一,区分异常和错误 

在 Java 中,所有的异常都封装成了对象。它们的最高祖先是 java.lang.Throwable。

Throwable: 异常界的“老祖宗”。

        Error (错误): 绝症。指 JVM 无法解决的严重问题(如:内存溢出 StackOverflowError)。程序员通常不处理它。

        Exception (异常): 感冒发烧。程序运行中出现的不正常情况,可以通过代码修复。

               1, 编译时异常 (Checked Exception): 编译器强制要求处理,不处理代码就跑不起来。

                2,运行时异常 (RuntimeException): 代码逻辑错误,编译器不强制要求处理。

 二,异常的分类

并非所有的异常都需要你立即处理。Java 根据异常发生的时机将其分为两类:

查型异常 (Checked Exception):

         编译器强制要求处理。就像出门前必须检查是否带了钥匙。

运行时异常 (Unchecked/Runtime Exception):

        编译器不强制,通常由代码逻辑错误引起。就像走在路上不小心踩到香蕉皮。

图表比较

特性受检异常 (Checked)运行时异常 (Unchecked/Runtime)
定义编译时必须处理的异常。编译时不强制要求处理。
发生时机通常由外部环境引起(如文件不存在)。通常由代码逻辑错误引起。
处理要求必须 try-catch 或 throws,否则代码无法通过编译。不强制要求,但好的习惯是提前检查代码逻辑。
常见例子IOException, SQLException。NullPointerException (空指针), ArrayIndexOutOfBounds (越界)。

三,常见的异常

1. 编译时异常 (Checked Exception) 

编译器在写代码时就会提醒你:“这里可能出事,你必须现在就写好应对方案!”

异常名称触发场景预防/解决办法

FileNotFoundException

文件找不到

程序想读 D:/test.txt,但文件根本不存在。检查路径是否正确,或先用 file.exists() 判断。

IOException

io异常

读写文件过程中突然断电、硬盘坏了或网络中断。必须使用 try-catch 包围,并确保在 finally 中关闭资源。

ClassNotFoundException

找不到类

反射加载类(如驱动)时,在 ClassPath 里找不到对应的 .class 文件。检查 Jar 包是否导入,类名拼写是否完全正确(包含包名)。

2. 运行时异常 (Unchecked Exception) 

编译器不强制要求处理,它们通常是由于程序员逻辑不严谨导致的“低级错误”。

异常名称触发场景预防/解决办法

NullPointerException

空指针异常

对 null 对象调用方法(如 String s=null; s.length();)。最重要:操作前先做非空判断 if (obj != null)。

ArrayIndexOutOfBounds

数组下标越界异常

数组长度为 3,你却访问 arr[3](下标从 0 开始,最大是 2)。检查循环边界,确保索引在 0 到 length-1 之间。

ArithmeticException

算数运算异常

进行了不合法的数学运算(如 10 / 0)。在做除法前,判断除数是否为 0。

ClassCastException

类型转型异常

强行把“狗”转成“猫”(如 Animal a = new Dog(); Cat c = (Cat)a;)。转型前使用 instanceof 进行类型检查。

NumberFormatException

数字格式化异常

把非数字字符串转成数字(如 Integer.parseInt("abc");)。转换前通过正则表达式校验字符串是否为纯数字。

四,异常的处理方式

 1,try-catch方式

一捕获三部曲:try - catch - finally

  • try: 包含可能出错的代码。

  • catch: 捕获具体的错误,并给出解决方案。

  • finally: 无论是否出错,一定执行的代码(用于关灯、关门、关闭资源)。

当运行 try错误时候-----(直接跳过当前位置进入到)-----catch 抛出异常

try {
    int result = 10 / 0; // 这里会发生除零错误
//当上面这一行出现错误了 try 语句下面的代码不会运行直接跳到  catch语句
            sout;
            sout;
            sout;
        //sout 不会在运行直接跳过 
        //如过没有问题 则会跳过catch 进入到 finally语句中

} catch (ArithmeticException e) {
        //抛出异常 抛出ArithmeticException 在控制台输出异常
        //ArithmeticException 只能捕获算数异常 可以使用 顶级异常Exception
    System.out.println("捕获到异常:除数不能为零!"); // 救场处理
} finally {
        //无论上面有没有异常 finally 语句都会运行
    System.out.println("不管出没出错,我都执行了。"); // 清理现场
}
 

   2、throws方式

throws方法声明异常,交给上层处理方法不知道如何处理异常(比如工具类方法)

   问题没有解决但是程序可以运行

import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;

// 定义一个读取文件的方法,声明抛出异常
public class ThrowsDemo {
    // 该方法声明抛出 FileNotFoundException 和 IOException
    public static void readFile(String filePath) throws FileNotFoundException, IOException {
        // 这里没有用 try-catch 处理异常,而是直接抛出
        FileReader reader = new FileReader(filePath);
        int data = reader.read();
        while (data != -1) {
            System.out.print((char) data);
            data = reader.read();
        }
        reader.close();
    }
}

        继续用 throws 抛给 JVM(不推荐,仅作示例)

public class Main {
    // main方法继续抛出异常,最终由JVM处理(会直接崩溃并打印异常栈)
    public static void main(String[] args) throws IOException {
        ThrowsDemo.readFile("test.txt");
    }
}

3,手动创建异常

new 一个对象  调用异常
throw new IllegalArgumentException("参数无效");
 

4,自定义异常

// 1. 自定义业务异常:继承 Exception(受检异常,必须显式处理)
public class InsufficientBalanceException extends Exception {
    // 构造方法1:仅传递异常信息
    public InsufficientBalanceException(String message) {
        // 调用父类的构造方法,传递异常描述信息
        super(message);
    }
    
    // 构造方法2:传递异常信息+原始异常(便于追踪异常链)
    public InsufficientBalanceException(String message, Throwable cause) {
        super(message, cause);
    }
}

// 2. 可选:自定义非受检异常(继承 RuntimeException,无需强制处理)
public class InvalidOrderIdException extends RuntimeException {
    public InvalidOrderIdException(String message) {
        super(message);
    }
}

手动创建异常 和自定义异常区别

维度手动创建 (使用内置异常)自定义异常 (创建新类)
本质直接 new 一个 Java 自带的异常类。先写一个类继承 Exception 或子类。
类名示例IllegalArgumentException。UserPowerInsufficientException。
可读性一般。只能通过错误信息(String)区分。极高。看类名就知道发生了什么业务错误。
开发成本极低。随拿随用。略高。需要额外写代码定义类。
适用场景通用的编程逻辑错误。特定的业务规则逻辑错误。

异常练习

public class CoffeeMachineDemo {

    /**
     * 制作咖啡的方法
     * @param waterAmount 水量(ml)
     * @param personCount 分享人数
     * @throws ArithmeticException 声明:如果人数为0,会抛出算数异常
     */
    public static void makeCoffee(int waterAmount, int personCount) throws ArithmeticException {
        System.out.println("【系统】启动加热程序...");

        // 1. 【手动创建并抛出异常】:逻辑检查
        if (waterAmount <= 0) {
            // 我们手动发现水量不对,主动按下警报
            throw new IllegalArgumentException("【报错】水箱没水了,当前水量:" + waterAmount);
        }

        // 2. 【自动触发异常】:JVM 发现错误
        // 如果 personCount 为 0,JVM 会在此处自动抛出 ArithmeticException
        int shareAmount = waterAmount / personCount; 

        System.out.println("【成功】每人分得咖啡: " + shareAmount + "ml");
    }

    public static void main(String[] args) {
        // 3. 【捕获处理】:try-catch-finally 组合拳
        try {
            System.out.println(">> 用户按下按钮:准备制作咖啡...");
            
            // --- 模拟调用(测试题目就在这里) ---
            makeCoffee(300, 0); 
            
            System.out.println(">> 咖啡制作完成,请享用!");

        } catch (IllegalArgumentException e) {
            // 捕获【手动】抛出的异常
            System.err.println("【处理警报】" + e.getMessage());

        } catch (ArithmeticException e) {
            // 捕获【自动】触发的异常
            System.err.println("【处理故障】不能分给 0 个人!请检查人数输入。");

        } finally {
            // 无论出不出错,最后都要关闭电源
            System.out.println("【系统】咖啡机进入待机模式,电源已切断。");
        }
    }
}
 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐