杰瑞科技汇

throws与throw到底有啥区别?

核心概念一句话总结

  • throw主动抛出一个异常,它是动作,是创建并抛出异常对象的行为。
  • throws声明一个方法可能抛出哪些异常,它是声明,是告诉调用者“我可能会甩给你一些麻烦,你要准备好处理”。

throw 关键字

throw 用于在代码的任何地方手动抛出一个异常对象,这通常意味着你检测到了一个错误或异常情况,并决定中断当前方法的正常流程。

throws与throw到底有啥区别?-图1
(图片来源网络,侵删)

语法

throw new ExceptionType("异常信息");
  • ExceptionType:必须是 Throwable 类或其子类(如 Exception, RuntimeException, IOException 等)。
  • "异常信息":是可选的,但强烈推荐提供,因为它可以帮助调试。

工作原理

throw 语句被执行时:

  1. 创建一个指定类型的异常对象。
  2. 当前方法的执行立即停止。
  3. 异常对象被“抛出”,并沿着调用栈向上寻找能够处理它的 catch 块,如果找不到,程序就会终止。

使用场景

当你明确知道某个错误条件已经发生,需要中断程序流程时使用。

示例

public class CheckAge {
    public static void checkAge(int age) {
        // 如果年龄小于18,主动抛出一个 IllegalArgumentException
        if (age < 18) {
            // 创建一个异常对象并抛出
            throw new IllegalArgumentException("年龄必须大于或等于18岁!");
        }
        System.out.println("年龄验证通过:" + age);
    }
    public static void main(String[] args) {
        try {
            checkAge(16); // 调用方法,传入不符合条件的参数
            System.out.println("这行代码不会被执行。");
        } catch (IllegalArgumentException e) {
            // 捕获并处理 checkAge 方法抛出的异常
            System.out.println("捕获到异常: " + e.getMessage());
        }
        System.out.println("程序继续执行...");
    }
}

输出:

捕获到异常: 年龄必须大于或等于18岁!
程序继续执行...

throws 关键字

throws 用在方法签名中,用来声明该方法可能会抛出的一种或多种异常类型,它是一种“通知”机制,告诉方法的调用者:“我在执行过程中可能会发生这些异常,你需要处理它们”。

throws与throw到底有啥区别?-图2
(图片来源网络,侵删)

语法

修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2, ... {
    // 方法体
}

工作原理

  • throws 本身不会抛出异常,它只是声明。
  • 当一个方法使用 throws 声明了异常后,调用这个方法的代码必须处理这个异常,处理方式有两种:
    1. 使用 try-catch 块捕获并处理异常。
    2. 在自己的方法签名上继续使用 throws 声明,将异常向上传递给它的调用者。

使用场景

当一个方法内部调用了另一个可能抛出受检异常的方法,而你不想(或不能)在该方法内部处理它时,就可以使用 throws

示例

假设我们有一个读取文件的方法,它可能会抛出 IOException(这是一个受检异常,必须处理)。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileReaderExample {
    // 这个方法声明它可能会抛出 FileNotFoundException 和 IOException
    public void readFile(String filePath) throws FileNotFoundException, IOException {
        // FileInputStream 的构造函数可能会抛出 FileNotFoundException
        FileInputStream fis = new FileInputStream(filePath);
        // read() 方法可能会抛出 IOException
        int data = fis.read();
        while (data != -1) {
            System.out.print((char) data);
            data = fis.read();
        }
        fis.close();
    }
    public static void main(String[] args) {
        FileReaderExample example = new FileReaderExample();
        // main 方法调用 readFile,必须处理其声明的异常
        try {
            example.readFile("test.txt");
            System.out.println("\n文件读取成功。");
        } catch (FileNotFoundException e) {
            System.out.println("错误:文件未找到!");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println("错误:读取文件时发生IO异常!");
            e.printStackTrace();
        }
    }
}

throw vs throws 核心区别

特性 throw throws
含义 抛出一个异常对象 声明一个方法可能抛出异常
语法位置 方法体内部 方法签名,在参数列表之后
作用 手动中断程序流程,创建并抛出异常 告知调用者该方法可能产生的异常类型
与异常的关系 是一个动作,是异常的源头 是一个声明,是异常的声明
后续处理 抛出后,必须由 try-catch 捕获或程序终止 调用者必须使用 try-catch 或继续 throws
数量 一次只能 throw 一个异常 可以 throws 多个异常,用逗号隔开
异常类型 可以抛出任何 Throwable 的子类 通常用于声明受检异常,但也可以声明非受检异常

一个综合示例来理解两者的关系

public class ThrowAndThrowsDemo {
    // 方法一:声明它会抛出一个受检异常 IOException
    public void readFile() throws IOException {
        System.out.println("readFile: 准备读取文件...");
        // 模拟文件读取失败,手动抛出一个异常
        // 注意:这里也可以不 throw,而是调用一个会抛出 IOException 的方法
        // new FileInputStream("non_existent_file.txt");
        throw new IOException("无法打开文件,文件不存在或权限不足!");
    }
    // 方法二:声明它会抛出一个非受检异常 NullPointerException
    public void processObject(Object obj) throws NullPointerException {
        if (obj == null) {
            // 手动抛出一个运行时异常
            throw new NullPointerException("传入的对象不能为 null!");
        }
        System.out.println("processObject: 对象处理成功。");
    }
    // 方法三:它调用了可能抛出异常的方法,并选择自己处理
    public void handleReadFileSafely() {
        try {
            System.out.println("handleReadFileSafely: 尝试调用 readFile...");
            readFile(); // 调用声明了 throws 的方法
        } catch (IOException e) {
            System.out.println("handleReadFileSafely: 捕获到并处理了 IOException。");
            e.printStackTrace();
        }
    }
    // 方法四:它调用了可能抛出异常的方法,并选择继续向上抛出
    public void processAndReThrow() throws IOException {
        System.out.println("processAndReThrow: 调用 readFile 并选择不处理...");
        readFile(); // 调用声明了 throws 的方法
        // 因为 readFile 抛出 IOException,processAndReThrow 也必须 throws IOException
    }
    public static void main(String[] args) {
        ThrowAndThrowsDemo demo = new ThrowAndThrowsDemo();
        // 1. 调用自己处理异常的方法
        demo.handleReadFileSafely();
        System.out.println("--------------------");
        // 2. 调用选择重新抛出异常的方法
        try {
            demo.processAndReThrow();
        } catch (IOException e) {
            System.out.println("main: 捕获了 processAndReThrow 传递上来的 IOException。");
        }
        System.out.println("--------------------");
        // 3. 调用抛出非受检异常的方法
        try {
            demo.processObject(null); // 传入 null 触发异常
        } catch (NullPointerException e) {
            System.out.println("main: 捕获了 processObject 抛出的 NullPointerException。");
        }
        System.out.println("--------------------");
        // 4. 调用抛出非受检异常的方法,不使用 try-catch
        // 非受检异常是可选的,可以不处理,但程序会中断
        System.out.println("准备调用 processObject(null) 且不捕获异常...");
        demo.processObject(null); // 程序会在这里抛出异常并终止
        System.out.println("这行代码不会被执行。");
    }
}
  • throw 是你作为程序员,在代码中主动制造一个异常事件。
  • throws 是你作为方法的设计者,向方法的使用者发出一个警告:“小心,我这里可能会出问题”。

理解了这两个角色的区别,就能很好地掌握 Java 的异常处理机制了。throw 是“行动派”,throws 是“声明派”。

throws与throw到底有啥区别?-图3
(图片来源网络,侵删)
分享:
扫描分享到社交APP
上一篇
下一篇