一,区分异常和错误 

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

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

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

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

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

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

 二,异常的分类

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

查型异常 (Checked Exception):

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

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

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

图表比较

特性 受检异常 (Checked) 运行时异常 (Unchecked/Runtime)
定义 编译时必须处理的异常。 编译时不强制要求处理。
发生时机 通常由外部环境引起(如文件不存在)。 通常由代码逻辑错误引起。
处理要求 必须 try-catchthrows,否则代码无法通过编译。 不强制要求,但好的习惯是提前检查代码逻辑。
常见例子 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)。 检查循环边界,确保索引在 0length-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编程工具,助力开发者即刻编程。

更多推荐