异常处理

异常处理让程序更健壮,本课学习Java中的异常处理机制。

什么是异常

异常是程序运行时发生的错误。

异常分类

TEXT
Throwable
├── Error(严重错误,程序无法处理)
│   ├── OutOfMemoryError
│   └── StackOverflowError
└── Exception(异常,程序可以处理)
    ├── 受检异常(必须处理)
    │   ├── IOException
    │   └── SQLException
    └── 非受检异常(RuntimeException)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        └── NumberFormatException

try-catch

语法

JAVA
try {
    // 可能抛出异常的代码
} catch (异常类型 变量名) {
    // 处理异常
}

示例:基本异常处理

JAVA
public class TryCatchDemo {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("发生算术异常:" + e.getMessage());
        }
        System.out.println("程序继续执行");
    }
}
▶ 试一试

输出:

TEXT
发生算术异常:/ by zero
程序继续执行

多个catch

JAVA
try {
    // 可能抛出多种异常的代码
} catch (异常类型1 e1) {
    // 处理异常1
} catch (异常类型2 e2) {
    // 处理异常2
} catch (Exception e) {
    // 处理其他异常
}

示例:多个catch

JAVA
public class MultiCatch {
    public static void main(String[] args) {
        try {
            String s = "abc";
            int num = Integer.parseInt(s);
            int result = 10 / num;
        } catch (NumberFormatException e) {
            System.out.println("数字格式错误:" + e.getMessage());
        } catch (ArithmeticException e) {
            System.out.println("算术错误:" + e.getMessage());
        } catch (Exception e) {
            System.out.println("其他错误:" + e.getMessage());
        }
    }
}
▶ 试一试

try-catch-finally

finally块无论是否发生异常都会执行。

语法

JAVA
try {
    // 可能抛出异常的代码
} catch (异常类型 e) {
    // 处理异常
} finally {
    // 无论是否异常都会执行
}

示例:finally

JAVA
public class FinallyDemo {
    public static void main(String[] args) {
        try {
            System.out.println("try块");
            int result = 10 / 0;
        } catch (ArithmeticException e) {
            System.out.println("catch块");
        } finally {
            System.out.println("finally块");
        }
    }
}
▶ 试一试

输出:

TEXT
try块
catch块
finally块

示例:资源释放

JAVA
import java.io.*;

public class ResourceDemo {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("test.txt");
            // 读取文件
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在");
        } finally {
            // 释放资源
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
▶ 试一试

try-with-resources

Java 7引入,自动关闭资源。

语法

JAVA
try (资源类型 变量 = new 资源()) {
    // 使用资源
} catch (异常类型 e) {
    // 处理异常
}

示例:try-with-resources

JAVA
import java.io.*;

public class TryWithResources {
    public static void main(String[] args) {
        // 自动关闭资源
        try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
            String line = reader.readLine();
            System.out.println(line);
        } catch (IOException e) {
            System.out.println("读取错误:" + e.getMessage());
        }
        // reader自动关闭,不需要finally
    }
}
▶ 试一试

throw和throws

throw:抛出异常

JAVA
public static int divide(int a, int b) {
    if (b == 0) {
        throw new ArithmeticException("除数不能为0");
    }
    return a / b;
}

throws:声明异常

JAVA
public static void readFile(String path) throws FileNotFoundException {
    FileReader reader = new FileReader(path);
}

示例:throw和throws

JAVA
public class ThrowDemo {
    public static int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("除数不能为0");
        }
        return a / b;
    }
    
    public static void validateAge(int age) {
        if (age < 0 || age > 150) {
            throw new IllegalArgumentException("年龄不合法:" + age);
        }
    }
    
    public static void main(String[] args) {
        try {
            System.out.println(divide(10, 0));
        } catch (ArithmeticException e) {
            System.out.println(e.getMessage());  // 除数不能为0
        }
        
        try {
            validateAge(-5);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());  // 年龄不合法:-5
        }
    }
}
▶ 试一试

自定义异常

步骤

  1. 继承Exception或RuntimeException
  2. 提供构造方法

示例:自定义异常

JAVA
// 自定义异常类
public class InsufficientBalanceException extends Exception {
    private double balance;
    private double amount;
    
    public InsufficientBalanceException(double balance, double amount) {
        super("余额不足:余额" + balance + ",取款" + amount);
        this.balance = balance;
        this.amount = amount;
    }
    
    public double getBalance() {
        return balance;
    }
    
    public double getAmount() {
        return amount;
    }
}

// 使用自定义异常
public class BankAccount {
    private double balance;
    
    public BankAccount(double balance) {
        this.balance = balance;
    }
    
    public void withdraw(double amount) throws InsufficientBalanceException {
        if (amount > balance) {
            throw new InsufficientBalanceException(balance, amount);
        }
        balance -= amount;
        System.out.println("取款成功,余额:" + balance);
    }
    
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000);
        
        try {
            account.withdraw(500);   // 取款成功,余额:500.0
            account.withdraw(800);   // 抛出异常
        } catch (InsufficientBalanceException e) {
            System.out.println(e.getMessage());
            System.out.println("余额:" + e.getBalance());
            System.out.println("取款:" + e.getAmount());
        }
    }
}
▶ 试一试

常见异常

异常 说明 原因
NullPointerException 空指针 对象为null时调用方法
ArrayIndexOutOfBoundsException 数组越界 访问不存在的索引
NumberFormatException 数字格式错误 字符串转数字失败
ClassCastException 类型转换错误 向下转型类型不匹配
ArithmeticException 算术错误 除以0
FileNotFoundException 文件不存在 文件路径错误
IOException IO错误 读写文件失败

异常处理原则

原则 说明
具体异常优先 先catch具体异常,再catch通用异常
不要忽略异常 至少打印日志
finally释放资源 或用try-with-resources
不要用异常控制流程 异常是处理错误的,不是控制流程的

❓ 常见问题

Q Error和Exception有什么区别?
A Error是严重错误,程序无法处理。Exception是异常,程序可以捕获处理。
Q 受检异常和非受检异常有什么区别?
A 受检异常必须处理(try-catch或throws)。非受检异常可以不处理。
Q 什么时候自定义异常?
A 需要区分业务异常类型时,如余额不足、用户不存在等。

📖 小节

📝 作业

  1. 异常处理: 编写方法读取文件,处理文件不存在和读取错误
  2. 自定义异常: 定义AgeOutOfBoundsException,验证年龄
  3. 资源管理: 用try-with-resources实现文件复制

下一课

下一课我们将学习 实战:面向对象,综合运用面向对象知识。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏