[认识异常和错误]java

一.认识异常(Exception),故障(Fault)和错误(error)

java中,一切皆对象。异常和错误也是对象!

1.1、 异常(Exception)(Java 核心概念)

定义

程序运行期间预料之内的不正常情况 ,通常由程序逻辑、输入数据、外部依赖(如文件不存在、网络超时)等问题引发,可以被开发者捕获并处理,从而让程序继续执行而非直接崩溃。

Java 中ExceptionThrowable的子类,分为受检异常(Checked Exception)非受检异常(Unchecked Exception/RuntimeException)

  1. 受检异常 (编译期强制检查):必须显式捕获或声明抛出,如IOExceptionSQLException

    java

    运行

    复制代码
    // 示例:文件读取的受检异常
    import java.io.FileReader;
    public class ExceptionDemo {
        public static void main(String[] args) {
            try {
                FileReader fr=new FileReader("test.txt"); // 可能抛出FileNotFoundException
            } catch (Exception e) {
                e.printStackTrace(); // 捕获并处理,程序不会崩溃
            }
        }
    }
  2. 非受检异常 (运行期抛出):通常是代码逻辑错误,如NullPointerExceptionArrayIndexOutOfBoundsException,无需强制声明

    java

    运行

    复制代码
    // 空指针异常(非受检)
    public class RuntimeExDemo {
        public static void main(String[] args) {
            String s=null;
            System.out.println(s.length()); // 运行时抛出NPE
        }
    }

核心特征

  • 发生在应用层,由代码或外部输入导致
  • 可控、可恢复 :通过try-catch-finally捕获处理
  • 不影响 JVM 本身的运行,仅影响当前线程

1.2、 错误(Error)(Java 核心概念,系统级)

定义

程序运行期间预料之外的、严重的系统级问题 ,通常由 JVM 或底层系统资源耗尽引发,开发者几乎无法捕获并处理,一旦发生,JVM 通常会终止线程甚至整个程序。

Java 中ErrorThrowable的子类,典型例子:OutOfMemoryError(内存溢出)、StackOverflowError(栈溢出)、NoClassDefFoundError(类定义找不到)。

java

运行

复制代码
// 示例:栈溢出错误
public class ErrorDemo {
    public static void recursion() {
        recursion(); // 无限递归,耗尽栈空间
    }
    public static void main(String[] args) {
        try {
            recursion();
        } catch (StackOverflowError e) { // 理论可捕获,但无法恢复
            e.printStackTrace();
            // 此时JVM线程已损坏,无法正常执行后续逻辑
        }
    }
}

核心特征

  • 发生在JVM / 系统层,由底层资源或系统错误导致
  • 不可控、不可恢复:即使捕获,也无法修复底层问题
  • 通常导致当前线程终止,严重时会让 JVM 崩溃

1.3、 故障(Fault)(通用工程 / 运维概念,非 Java 语法)

定义

系统组件或硬件的永久性 / 临时性缺陷 ,是导致错误或异常的根本原因,多用于分布式系统、运维领域。例如:服务器宕机、网络链路中断、数据库主从同步失败、磁盘坏道等。

故障本身不是代码层面的概念,而是基础设施层面的问题,会间接引发程序的异常或错误。

  • 示例 1:数据库服务器故障(宕机)→ 程序抛出SQLException(异常)
  • 示例 2:磁盘故障(坏道)→ JVM 读取类文件失败,抛出NoClassDefFoundError(错误)

核心特征

  • 发生在基础设施 / 硬件 / 第三方服务层
  • 通常是外部问题,程序本身无法直接修复
  • 影响范围大,可能导致多个服务 / 线程异常

1.4、 核心对比表格

维度 异常(Exception) 错误(Error) 故障(Fault)
归属 Java 语法,应用层 Java 语法,JVM / 系统层 工程概念,基础设施层
引发原因 逻辑错误、输入异常、外部依赖异常 JVM 资源耗尽、系统错误 硬件损坏、服务宕机、网络中断
可控性 可捕获、可处理、可恢复 几乎不可控、不可恢复 需运维干预修复(如重启服务、更换硬件)
影响范围 单个线程 / 方法 单个线程 / JVM 多个服务 / 整个系统
典型例子 IOException、NullPointerException OutOfMemoryError、StackOverflowError 服务器宕机、磁盘坏道、网络分区

1.5、 补充说明与区分技巧

  1. 异常 vs 错误(Java 中):看Throwable的子类,Exception是应用级问题,Error是 JVM 级问题

    java

    运行

    复制代码
    // Java中Throwable的继承结构
    Throwable
    ├─ Exception(受检/非受检)
    └─ Error(系统级错误)
  2. 故障 vs 异常 / 错误:故障是根因 ,异常 / 错误是故障的结果 。例如:网络故障 → 程序抛出SocketException(异常)

  3. 处理建议

    • 异常:必须用try-catch处理受检异常,非受检异常通过代码规范避免(如判空、边界检查)
    • 错误:无需主动捕获,通过监控告警(如内存监控、栈监控)提前预防
    • 故障:通过熔断、降级、重试等架构设计(如 Sentinel、Resilience4j)降低影响

二.Exception

2.1分类

编译时异常:

又叫受检异常。这个系列的异常,只要可能发生,编译器都会报错,提示你必须做出处理的操作。否则编译不通过,比如:IOException

运行时异常:

又叫非受检异常。这个系列的异常,无论是不是真的会发生,编译器都会视而不见,不会给出任何提示,只有在程序运行时才会暴露问题。例如:ArrayIndexOutOfBoundsException,NullPointException(用null对象来.方法),ClassCastException(类型转换异常),ArithmeticException(算术异常),InputMismatchException(输入不匹配异常)

三.异常处理

3.1语法格式

3.2try-catch结构

3.3求两数之商的异常处理

复制代码
import org.junit.jupiter.api.Test;

import java.util.Scanner;

public class TestDivide {
    /*
    nextInt报错后,不会读入这个数据对吧,然后这个数据放在栈的缓冲区,需要我们nextLine读取掉但是不接受对吗?然后下次循
    环就把它清出缓冲区对吗

    *  你的理解与实际情况对照
        你的理解: nextInt 报错后,不会读入这个数据对吧?
      实际情况: 完全正确 。
        当 nextInt() 发现输入流里的下一个标记(token)不是整数时,它会直接抛出异常并停止工作,它不会把这个错误的数据取走。
        你的理解: 然后这个数据放在栈的缓冲区...
      实际情况: 这个数据是放在 Scanner 的输入缓冲区(Buffer) 中,或者更准确地说,是留在 System.in 的流中。
        纠正点:这里通常不叫“栈的缓冲区”。在计算机中,“栈”通常指方法调用栈。这里的存储区域更准确的叫法是 缓冲区(Buffer) 或 输入流(InputStream)27。
        你的理解: 需要我们 nextLine 读取掉但是不接受对吗?
      实际情况: 完全正确 。
        我们调用 sc.nextLine() 的目的就是为了消耗(consume)掉这个残留在缓冲区里的错误数据。我们不需要把这个读取的值赋给任何变量(或者说,即使赋值了我们也不处理),目的仅仅是把它从缓冲区里“清空”13。
        你的理解: 然后下次循环就把它清出缓冲区对吗?
      实际情况: 逻辑正确。
        执行完 nextLine() 后,缓冲区就被清空了。当 catch 块执行完毕,while 循环开始下一次迭代时,nextInt() 就会发现缓冲区是空的,从而停下来等待用户输入新的数据,而不是卡在旧的错误数据上26。
    * */
    @Test
    public void testDivide() {
        int a ,b;
        Scanner sc = new Scanner(System.in);
        while (true) {
            try {
                System.out.println("请输入第一个个数字a:");
                a = sc.nextInt();
                break;
            } catch (Exception e) {
                e.printStackTrace();//打印异常的详细信息,包装异常的堆栈跟踪信息,类型,异常的message等。
                sc.nextLine();//这句代码是把当前输入的数据整行全部读取掉,但不接收,只是把数据丢弃。
            }
        }
        while (true) {
            try {
                System.out.println("请输入第二个数字b:");
                b = sc.nextInt();
                if(b != 0)
                    break;
                else
                    System.out.println("除数不能为0!");
            } catch (Exception e) {
                e.printStackTrace();
                sc.nextLine();
            }
        }
        double c = (double)a / b;
        System.out.println("a / b = " + c);
        sc.close();
    }
}
相关推荐
码农水水2 小时前
中国电网Java面试被问:流批一体架构的实现和状态管理
java·c语言·开发语言·面试·职场和发展·架构·kafka
1***43802 小时前
C++跨平台开发的核心挑战线程管理等基础功能
开发语言·c++
做萤石二次开发的哈哈2 小时前
萤石开放平台 萤石可编程设备 | 设备脚本自定义开发
开发语言·python·萤石云·萤石·萤石开放平台
程序员清风2 小时前
猿辅导二面:线上出现的OOM是如何排查的?
java·后端·面试
无风听海2 小时前
深入讲解 C# 中 string 如何支持 CultureInfo
开发语言·c#
yaoxin5211232 小时前
291. Java Stream API - 从正则表达式创建 Stream
java·开发语言
BHXDML2 小时前
Java 设计模式详解
java·开发语言·设计模式
BD_Marathon2 小时前
MyBatis核心配置文件之mappers
java·数据库·mybatis