JavaSE基础——第十章 异常处理(二)

本专题主要为观看韩顺平老师《零基础30天学会Java》课程笔记,同时也会阅读其他书籍、学习其他视频课程进行学习笔记总结。如有雷同,不是巧合!

 三、异常处理机制

异常处理机制是一种结构化的错误处理方式,用于管理程序运行时可能出现的异常情况(如文件不存在、网络中断、空指针访问等)。它允许程序在遇到错误时进行合理的处理,而不是直接崩溃。剩下的程序会继续执行。

-Java 提供了三种主要的异常处理机制:

1. try-catch-finally

程序员在代码中捕获发生的异常,并自行处理。

try {
    // 可能抛出异常的代码
} catch (ExceptionType1 e1) {
		// 将异常发生时,系统将异常封装成Exception对象e,并传递给catch
    // 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型的异常
} finally {
    // 无论是否发生异常都会执行的代码
    // 常用于资源清理
    // 如果没有finally,语法也可以通过
}

  • 可以直接用try-finally,相当于没有捕获异常,程序会直接崩掉(finally后),但在finally中的块还是会执行。

  • finally 块中的 return 语句会覆盖 trycatch 块中的 return 语句:
    • finally 块的设计初衷是无论发生什么(正常执行、异常抛出、try/catch 中有 return),finally 块中的代码都必须被执行。这个“必须执行”的原则优先级非常高。
  • 例题:

题目1:

catch 块中遇到 return 3; 时,JVM 并不会立即结束方法调用。它的执行流程如下:

  1. catch 块开始执行:JVM 准备返回 3
  2. 暂停返回操作:在真正返回之前,JVM 必须先去执行 finally 块,因为这是语言规范强制要求的
  3. 执行 finally 块:进入 finally 块后,执行 return 4;
  4. finally 中的 return 生效finally 块中的 return 4; 现在成为新的返回指令
  5. 忽略之前的返回值catch 块中准备的 return 3; 被完全忽略和覆盖

题目2:

  1. catch (NullPointerException e) 捕获异常,执行 return ++i;
    1. i 先自增为 3,然后 return 3;(此时 3 被存入临时变量,但还未真正返回)
  2. finally 块执行
    1. ++i; → i 变为 4
    2. System.out.println("i=" + i); → 打印 i=4
    3. finally 块没有 return,所以不会覆盖 catch 的返回值
  3. 最终返回值catch 块返回的是 3(临时变量存储的值),因此 main 方法打印

  • 例题:如果用户输入的不是一个整数,就提醒他反复输入,直到输入一个整数为止。

    方法一:使用 Scannertry-catch

    import java.util.Scanner;
    import java.util.InputMismatchException;
    
    public class IntegerInputValidation {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int number = 0;
            boolean validInput = false;
    
            while (!validInput) {
                try {
                    System.out.print("请输入一个整数: ");
                    number = scanner.nextInt();
                    validInput = true;  // 只有成功读取整数才会执行到这里
                } catch (InputMismatchException e) {
                    System.out.println("错误:请输入有效的整数!");
                    scanner.nextLine(); // ⭐清除输入缓冲区中的错误内容
                }
            }
    
            System.out.println("您输入的整数是: " + number);
            scanner.close();
        }
    }
    

    通过捕获 InputMismatchExceptionScanner 特有的异常),直到获得合法整数。

    import java.util.Scanner;
    
    public class Solution {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            String input;
            int num;
            while (true) {
                try {
                    System.out.print("输入一个整数:");
                    input = scanner.nextLine();
                    num = Integer.parseInt(input);
                    break;
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("输入的整数是:" + num);
        }
    }
    

    方法二:使用 BufferedReaderNumberFormatException

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class IntegerInputValidation2 {
        public static void main(String[] args) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            int number = 0;
            boolean validInput = false;
    
            while (!validInput) {
                try {
                    System.out.print("请输入一个整数: ");
                    String input = reader.readLine();
                    number = Integer.parseInt(input);
                    validInput = true;
                } catch (NumberFormatException e) {
                    System.out.println("错误:请输入有效的整数!");
                } catch (IOException e) {
                    System.out.println("输入输出错误!");
                }
            }
    
            System.out.println("您输入的整数是: " + number);
        }
    }
    

    捕获 NumberFormatException(字符串转数字时的异常),每次读取新的一行,不需要额外处理。

2. throws 关键字

将发生的异常抛出,交给调用者(方法)处理,最顶级的处理者是JVM【打印异常信息,并直接退出程序】。

public void readFile(String filePath) throws IOException, FileNotFoundException {
    // 可能抛出 IOException 的代码
}

如果出现运行时异常,没有使用try-catch处理,会有默认的throws Exception动作,如果调用它的方法没有处理,则默认丢给JVM。

  • 子类重写父类的方法时,所抛出的异常要么和父类抛出的异常一致,要么是父类抛出的异常类型的子类型。

  • 如果一个方法具有编译异常,则必须显式抛出或者用try-catch处理异常;调用它的方法(直到main)也是同样的要求(最终必须有一个方法处理异常(否则编译失败)) ,否则代码将无法通过编译。

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    public class Solution {
        public static void main(String[] args) {
            f1();
        }
    
        public static void f1() {
            f3();
        }
    
        public static void f3() {
            FileInputStream fis = new FileInputStream("1111.txt");
        }
    }
    
  • 不是每个方法都必须 try-catch,可以选择:
    • 当前方法处理(try-catch
    • 继续向上抛出(throws
public static void main(String[] args) {
    try {
        methodA(); // 最终在 main 处理异常
    } catch (IOException e) {
        System.out.println("main 处理异常: " + e.getMessage());
    }
}

static void methodA() throws IOException {
    methodB(); // 不处理,继续向上抛出
}

static void methodB() throws IOException {
    throw new IOException("IO错误!");
}

3. throw 关键字

使用 throw 关键字可以显式抛出异常:

if (someCondition) {
    throw new IllegalArgumentException("Invalid argument");
}

四、自定义异常

当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,可以创建自己的异常类来代表特定的错误情况。

自定义异常的步骤

  1. 定义异常类名,并继承ExceptionRuntimeException
  2. 如果继承Exception,输入编译异常
  3. 否则属于运行异常【通常情况】,可以使用默认的处理机制,否则下图的main方法要显式地throws AgeException

五、throw&throws

1. throw 关键字

作用:主动抛出一个异常对象(可以是 checked exception 或 unchecked exception)。

特点

  • 用于方法内部
  • 后面跟一个异常对象实例
  • 执行到 throw 语句时,当前方法会立即终止

语法

throw new ExceptionType("异常信息");

示例

void validateAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("年龄不能为负数");
    }
    if (age > 120) {
        throw new RuntimeException("年龄不合法");
    }
}

2. throws 关键字

作用:在方法签名中声明该方法可能抛出的异常类型。

可以声明运行时异常(RuntimeException 及其子类),但这样做通常没有实际意义,因为运行时异常是 unchecked exceptions(非受检异常),调用方并不强制要求处理它们。

特点

  • 用于方法声明处
  • 后面跟一个或多个异常类名
  • 不实际抛出异常,只是声明可能性
  • 调用该方法的地方必须处理这些异常

语法

returnType methodName(parameters) throws ExceptionType1, ExceptionType2 {...}

示例

void readFile(String path) throws FileNotFoundException, IOException {
    // 方法实现可能抛出这些异常
}

对比

特性throwthrows
位置方法内部方法声明处
作用主动抛出异常声明可能抛出的异常
后跟内容异常对象实例(new Exception()异常类名(Exception.class
数量一次只能抛出一个异常可以声明多个异常(逗号分隔)
异常类型可以是 checked 或 unchecked只能是 checked exceptions

组合使用示例

throw抛出编译异常,必须捕获或throws抛出让调用方法处理;抛出运行时异常,不需要强制处理。

// 声明可能抛出IOException(throws)
public void processFile(String filename) throws IOException {
    if (filename == null) {
        // 主动抛出异常(throw)
        throw new IllegalArgumentException("文件名不能为null");
    }

    BufferedReader reader = new BufferedReader(new FileReader(filename));
    // 这里可能抛出FileNotFoundException(是IOException的子类)
    String line = reader.readLine();
    reader.close();
}
  • 例题:

    finally块执行完后,才会回来执行try或catch中的return或throw语句,若finally中有return或throw等终止访问的语句,则不会跳回执行,直接停止

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值