Java异常处理完全指南:轻松搞定运行时与编译时异常!
📌 一、异常到底是什么?
想象一下:你正在运行一个Java程序,突然程序"崩溃"了——这通常就是异常在作祟!
// 典型的异常场景publicclassDailyExample{publicstaticvoidmain(String[]args){// 场景1:读取不存在的文件 ❌readFile("不存在的文件.txt");// 场景2:除以零 ❌calculate(10,0);// 场景3:访问空对象 ❌Stringtext=null;printLength(text);}}异常(Exception)就是程序运行时的"意外事件",它打断了正常的指令流。Java提供了一套完善的异常处理机制,让我们能够优雅地处理这些意外。
🏗️ 二、Java异常家族树
📦 Throwable (所有异常/错误的祖宗) ├── 🔴 Error (严重错误,程序无法处理) │ ├── OutOfMemoryError (内存溢出) │ ├── StackOverflowError (栈溢出) │ └── VirtualMachineError (虚拟机错误) │ └── 🟡 Exception (异常,可以处理) ├── 🟢 RuntimeException (运行时异常) │ ├── NullPointerException (空指针) │ ├── ArrayIndexOutOfBoundsException (数组越界) │ ├── ClassCastException (类型转换错误) │ ├── IllegalArgumentException (非法参数) │ └── ArithmeticException (算术异常) │ └── 🔵 其他Exception (编译时异常) ├── IOException (IO异常) ├── SQLException (数据库异常) ├── FileNotFoundException (文件未找到) └── ClassNotFoundException (类未找到)🔍 关键区别速记:
Error:天灾人祸,程序救不了 ❌
Exception:小病小痛,程序能自救 ✅
🆚 三、核心对决:运行时异常 vs 编译时异常
🟢 运行时异常(RuntimeException)
特点:编译器不检查,出了事才处理
别名:非受检异常(Unchecked Exception)
心态:“代码有风险,运行需谨慎”
publicclassRuntimeDemo{publicstaticvoidmain(String[]args){// 1️⃣ 空指针异常 - 最常见的异常!Stringname=null;// System.out.println(name.length()); // 运行时崩溃!// 2️⃣ 数组越界异常int[]scores={90,85,95};// System.out.println(scores[10]); // 运行时崩溃!// 3️⃣ 类型转换异常Objectobj="我是字符串";// Integer num = (Integer) obj; // 运行时崩溃!// 4️⃣ 算术异常// int result = 100 / 0; // 运行时崩溃!}}处理建议:虽然编译器不强制,但重要逻辑一定要处理!
🔵 编译时异常(Checked Exception)
特点:编译器强制检查,不处理就编译失败
别名:受检异常
心态:“提前预防,必须处理”
importjava.io.*;publicclassCheckedDemo{// ❌ 不处理会编译报错!// public void readFile() {// FileReader reader = new FileReader("test.txt");// }// ✅ 方案1:try-catch处理publicvoidreadFileWithTryCatch(){try{FileReaderreader=newFileReader("test.txt");System.out.println("文件读取成功!");}catch(FileNotFoundExceptione){System.out.println("文件不存在,创建默认配置...");// 恢复逻辑}}// ✅ 方案2:throws声明publicvoidreadFileWithThrows()throwsIOException{FileReaderreader=newFileReader("test.txt");// 继续抛出,让调用者处理}}🛠️ 四、异常处理四大法宝
法宝1️⃣:try-catch-finally(基础必备)
publicclassTryCatchDemo{publicvoidprocessOrder(StringorderId){Connectionconn=null;try{System.out.println("开始处理订单: "+orderId);// 1. 连接数据库conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/db");// 2. 业务处理(可能抛出异常)validateOrder(orderId);updateInventory(orderId);sendNotification(orderId);System.out.println("订单处理成功!");}catch(SQLExceptione){System.out.println("数据库操作失败: "+e.getMessage());// 记录日志,发送告警log.error("订单处理失败",e);}catch(IllegalArgumentExceptione){System.out.println("订单参数错误: "+e.getMessage());// 返回错误给用户}catch(Exceptione){System.out.println("未知错误: "+e.getMessage());// 兜底处理}finally{// 3. 无论如何都要执行!System.out.println("执行清理工作...");if(conn!=null){try{conn.close();// 释放资源}catch(SQLExceptione){System.out.println("关闭连接失败");}}}}}法宝2️⃣:try-with-resources(优雅关闭)
// Java 7+ 自动资源管理,告别finally!publicclassModernResourceDemo{publicvoidreadConfigFile(Stringpath){// 资源自动关闭,像魔术一样!try(FileInputStreamfis=newFileInputStream(path);BufferedReaderreader=newBufferedReader(newInputStreamReader(fis))){Stringline;while((line=reader.readLine())!=null){System.out.println(line);}}catch(IOExceptione){System.out.println("配置文件读取失败: "+e.getMessage());}// 不用写finally!资源自动关闭}}法宝3️⃣:throw(主动抛出异常)
publicclassValidator{// 参数校验 - 主动抛出异常publicvoidregisterUser(Stringusername,Stringpassword){if(username==null||username.trim().isEmpty()){thrownewIllegalArgumentException("用户名不能为空!");}if(password==null||password.length()<6){thrownewIllegalArgumentException("密码长度至少6位!");}if(username.equals("admin")){thrownewSecurityException("不能使用admin用户名!");}System.out.println("用户注册成功: "+username);}}法宝4️⃣:throws(异常声明)
publicclassDataProcessor{// 声明可能抛出的异常publicvoidprocessUserData(StringuserId)throwsSQLException,DataFormatException{// 数据库操作可能抛出SQLExceptionUseruser=userDao.findById(userId);// 数据处理可能抛出自定义异常if(user.getData()==null){thrownewDataFormatException("用户数据格式错误");}// 业务逻辑...}}// 调用者需要处理这些异常classServiceLayer{publicvoidhandleUserRequest(StringuserId){DataProcessorprocessor=newDataProcessor();try{processor.processUserData(userId);}catch(SQLExceptione){System.out.println("数据库异常,请稍后重试");}catch(DataFormatExceptione){System.out.println("数据格式错误: "+e.getMessage());}}}代码踢调试
main.文件
packageorg.example;publicclassMain{publicstaticvoidmain(String[]args){// System.out.println(dis(10, 0));// 铺获 之后 代码还是能 往下面执行的try{test1();// Object o = null;// o.toString();}catch(NullPointerExceptione){// e.printStackTrace(); // 打印红色的报错/** * java.lang.NullPointerException: Cannot invoke "Object.toString()" because "o" is null * at org.example.Main.main(Main.java:9) * */// System.out.println(e);// System.out.println("try 发生了异常呗铺到了");System.out.println(e.getMessage());}catch(TestRunTimeExceptione){System.out.println(e.getMessage());}System.out.println("1111111111");}privatestaticvoidtest1(){thrownewTestRunTimeException("我是自定义异常");}protectedstaticintdis(inta,intb){if(b==0){// throw new TestRunTimeException("0 不能作为除数"); // 运行时会报错thrownewRuntimeException();// RuntimeException 可以传入参数}returna/b;}}TestException 文件
packageorg.example;// 编译时 异常publicclassTestExceptionextendsException{publicTestException(Stringmessage){super(message);}}TestRunTimeException 文件
packageorg.example;// RuntimeException 是 继承 Exception 的子类 见md文件publicclassTestRunTimeExceptionextendsRuntimeException{publicTestRunTimeException(Stringmessage){super(message);}}Error和Exception有什么区别?
Error是系统级错误,程序无法处理(如内存溢出);Exception是程序级异常,可以被捕获处理。
throw和throws的区别?
throw是抛出异常(动词),throws是声明异常(名词)。