当前位置: 首页 > news >正文

Java 运行时异常和编译时异常之间的区别是什么?

Java 中的异常分为两大类:运行时异常编译时异常(也称为检查型异常)。它们在处理方式、继承层次和使用场景上有重要区别。

异常层次结构

Throwable ├── Error(错误,不处理) └── Exception(异常) ├── RuntimeException(运行时异常,非检查型) │ ├── NullPointerException │ ├── ArrayIndexOutOfBoundsException │ ├── ArithmeticException │ ├── ClassCastException │ └── ... └── 其他异常(编译时异常,检查型) ├── IOException ├── SQLException ├── FileNotFoundException └── ...

主要区别对比

特性运行时异常编译时异常
继承类RuntimeExceptionException(非RuntimeException)
检查时机运行时编译时
必须处理不强制必须处理
声明要求不需要声明必须声明或捕获
常见例子NullPointerException, ArrayIndexOutOfBoundsExceptionIOException, SQLException
处理方式可选强制

运行时异常

特点

  • 继承自RuntimeException
  • 编译器不强制要求处理
  • 通常表示编程错误
  • 可以在代码中避免

常见运行时异常

// 1. NullPointerException - 空指针异常Stringstr=null;intlength=str.length();// NullPointerException// 2. ArrayIndexOutOfBoundsException - 数组越界int[]arr=newint[5];intvalue=arr[10];// ArrayIndexOutOfBoundsException// 3. ArithmeticException - 算术异常intresult=10/0;// ArithmeticException// 4. ClassCastException - 类型转换异常Objectobj="Hello";Integernum=(Integer)obj;// ClassCastException// 5. IllegalArgumentException - 非法参数异常publicvoidsetAge(intage){if(age<0||age>150){thrownewIllegalArgumentException("年龄必须在0-150之间");}}// 6. NumberFormatException - 数字格式异常intnum=Integer.parseInt("abc");// NumberFormatException// 7. IndexOutOfBoundsException - 索引越界List<String>list=newArrayList<>();Stringitem=list.get(0);// IndexOutOfBoundsException

运行时异常处理示例

publicclassRuntimeExceptionExample{// 不需要声明运行时异常publicintdivide(inta,intb){returna/b;// 可能抛出 ArithmeticException}// 可选处理运行时异常publicvoidprocessString(Stringstr){// 方式1:不处理(让调用者处理)intlength=str.length();// 方式2:主动检查避免异常if(str!=null){intlength2=str.length();}// 方式3:捕获处理try{intlength3=str.length();}catch(NullPointerExceptione){System.out.println("字符串为空");}}// 抛出自定义运行时异常publicvoidsetAge(intage){if(age<0||age>150){thrownewIllegalArgumentException("年龄必须在0-150之间");}}}

编译时异常

特点

  • 继承自Exception但不是RuntimeException
  • 编译器强制要求处理
  • 通常表示外部环境问题
  • 必须声明或捕获

常见编译时异常

// 1. IOException - 输入输出异常importjava.io.*;publicvoidreadFile(Stringfilename)throwsIOException{FileReaderreader=newFileReader(filename);// 必须声明 throws IOException}// 2. FileNotFoundException - 文件未找到异常publicvoidopenFile(Stringpath)throwsFileNotFoundException{FileInputStreamfis=newFileInputStream(path);// 必须声明 throws FileNotFoundException}// 3. SQLException - 数据库异常importjava.sql.*;publicvoidqueryData()throwsSQLException{Connectionconn=DriverManager.getConnection("jdbc:mysql://localhost/test");Statementstmt=conn.createStatement();ResultSetrs=stmt.executeQuery("SELECT * FROM users");// 必须声明 throws SQLException}// 4. ClassNotFoundException - 类未找到异常publicvoidloadClass(StringclassName)throwsClassNotFoundException{Class.forName(className);// 必须声明 throws ClassNotFoundException}// 5. InterruptedException - 中断异常publicvoidsleep()throwsInterruptedException{Thread.sleep(1000);// 必须声明 throws InterruptedException}// 6. ParseException - 解析异常importjava.text.*;publicvoidparseDate(StringdateStr)throwsParseException{SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-dd");Datedate=sdf.parse(dateStr);// 必须声明 throws ParseException}

编译时异常处理示例

importjava.io.*;importjava.sql.*;publicclassCheckedExceptionExample{// 方式1:声明异常(让调用者处理)publicvoidreadFile(Stringfilename)throwsIOException{FileReaderreader=newFileReader(filename);BufferedReaderbr=newBufferedReader(reader);Stringline=br.readLine();System.out.println(line);br.close();}// 方式2:捕获异常publicvoidreadFileSafe(Stringfilename){try{FileReaderreader=newFileReader(filename);BufferedReaderbr=newBufferedReader(reader);Stringline=br.readLine();System.out.println(line);br.close();}catch(IOExceptione){System.out.println("读取文件失败: "+e.getMessage());}}// 方式3:捕获后重新抛出publicvoidreadFileAndRethrow(Stringfilename)throwsCustomException{try{FileReaderreader=newFileReader(filename);BufferedReaderbr=newBufferedReader(reader);Stringline=br.readLine();System.out.println(line);br.close();}catch(IOExceptione){thrownewCustomException("文件处理失败",e);}}// 方式4:使用 try-with-resources(推荐)publicvoidreadFileWithResources(Stringfilename){try(FileReaderreader=newFileReader(filename);BufferedReaderbr=newBufferedReader(reader)){Stringline=br.readLine();System.out.println(line);}catch(IOExceptione){System.out.println("读取文件失败: "+e.getMessage());}}// 多个异常的处理publicvoidprocessFile(Stringfilename)throwsIOException,ClassNotFoundException{// 可以声明多个异常FileReaderreader=newFileReader(filename);Class.forName("com.example.SomeClass");}// 多个异常的捕获publicvoidhandleMultipleExceptions(Stringfilename){try{FileReaderreader=newFileReader(filename);Class.forName("com.example.SomeClass");}catch(IOException|ClassNotFoundExceptione){// Java 7+ 可以捕获多个异常System.out.println("处理异常: "+e.getMessage());}}}

实际应用场景对比

1.文件操作(编译时异常)

importjava.io.*;publicclassFileProcessor{// 编译时异常 - 必须处理publicvoidprocessFile(StringinputPath,StringoutputPath)throwsIOException{try(BufferedReaderreader=newBufferedReader(newFileReader(inputPath));BufferedWriterwriter=newBufferedWriter(newFileWriter(outputPath))){Stringline;while((line=reader.readLine())!=null){// 处理每一行Stringprocessed=processLine(line);writer.write(processed);writer.newLine();}}// IOException 是编译时异常,必须处理}privateStringprocessLine(Stringline){// 这里可能抛出运行时异常if(line==null){thrownewIllegalArgumentException("行不能为空");}returnline.toUpperCase();}}

2.数据库操作(编译时异常)

importjava.sql.*;publicclassDatabaseManager{publicUsergetUserById(intuserId)throwsSQLException{Connectionconn=null;PreparedStatementstmt=null;ResultSetrs=null;try{conn=DriverManager.getConnection("jdbc:mysql://localhost/mydb");Stringsql="SELECT * FROM users WHERE id = ?";stmt=conn.prepareStatement(sql);stmt.setInt(1,userId);rs=stmt.executeQuery();if(rs.next()){returnnewUser(rs.getInt("id"),rs.getString("name"));}returnnull;}finally{// 清理资源if(rs!=null)rs.close();if(stmt!=null)stmt.close();if(conn!=null)conn.close();}// SQLException 是编译时异常,必须处理}}

3.业务逻辑(运行时异常)

publicclassUserService{// 运行时异常 - 不需要声明publicvoidregisterUser(Stringusername,Stringpassword){// 参数验证 - 抛出运行时异常if(username==null||username.trim().isEmpty()){thrownewIllegalArgumentException("用户名不能为空");}if(password==null||password.length()<6){thrownewIllegalArgumentException("密码长度不能少于6位");}// 检查用户名是否已存在if(userExists(username)){thrownewIllegalStateException("用户名已存在");}// 保存用户saveUser(username,password);}// 运行时异常 - 不需要声明publicUsergetUser(intuserId){Useruser=userRepository.findById(userId);if(user==null){thrownewUserNotFoundException("用户不存在: "+userId);}returnuser;}// 自定义运行时异常publicstaticclassUserNotFoundExceptionextendsRuntimeException{publicUserNotFoundException(Stringmessage){super(message);}}}

异常处理最佳实践

1.何时使用运行时异常

// ✅ 适合使用运行时异常的情况publicclassBankAccount{privatedoublebalance;publicvoidwithdraw(doubleamount){// 编程错误 - 应该在调用前检查if(amount<0){thrownewIllegalArgumentException("取款金额不能为负数");}// 业务规则违反 - 运行时异常if(amount>balance){thrownewIllegalStateException("余额不足");}balance-=amount;}publicvoiddeposit(doubleamount){// 参数验证if(amount<=0){thrownewIllegalArgumentException("存款金额必须大于0");}balance+=amount;}}

2.何时使用编译时异常

// ✅ 适合使用编译时异常的情况publicclassFileDownloader{publicvoiddownloadFile(Stringurl,StringsavePath)throwsIOException{// 文件操作 - 外部环境问题,使用编译时异常URLwebsite=newURL(url);ReadableByteChannelrbc=Channels.newChannel(website.openStream());FileOutputStreamfos=newFileOutputStream(savePath);fos.getChannel().transferFrom(rbc,0,Long.MAX_VALUE);}publicvoidprocessDownloadedFile(StringfilePath)throwsIOException,ParseException{// 多个可能的编译时异常BufferedReaderreader=newBufferedReader(newFileReader(filePath));Stringcontent=reader.readLine();// 解析日期SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-dd");Datedate=sdf.parse(content);}}

3.异常处理策略

publicclassExceptionHandlingStrategy{// 策略1:恢复并继续publicvoidprocessMultipleFiles(List<String>filePaths){for(StringfilePath:filePaths){try{processFile(filePath);}catch(IOExceptione){// 记录错误但继续处理其他文件System.err.println("处理文件失败: "+filePath+", 错误: "+e.getMessage());}}}// 策略2:转换异常类型publicUserloadUser(intuserId)throwsUserLoadException{try{returnuserRepository.findById(userId);}catch(SQLExceptione){// 将底层异常转换为业务异常thrownewUserLoadException("加载用户失败",e);}}// 策略3:提供默认值publicStringgetConfigValue(Stringkey){try{returnconfigLoader.load(key);}catch(IOExceptione){// 返回默认值而不是抛出异常return"default";}}// 自定义业务异常publicstaticclassUserLoadExceptionextendsException{publicUserLoadException(Stringmessage,Throwablecause){super(message,cause);}}}

异常处理注意事项

✅ 推荐做法

// 1. 具体异常处理try{// 代码}catch(FileNotFoundExceptione){// 处理文件未找到}catch(IOExceptione){// 处理其他IO异常}// 2. 提供有意义的错误信息thrownewIllegalArgumentException("年龄必须在0-150之间,当前值: "+age);// 3. 保留原始异常信息try{// 代码}catch(IOExceptione){thrownewBusinessException("处理失败",e);}// 4. 清理资源try(FileReaderreader=newFileReader("file.txt")){// 使用资源}catch(IOExceptione){// 处理异常}

❌ 避免的做法

// 1. 捕获所有异常try{// 代码}catch(Exceptione){// 太宽泛,难以处理}// 2. 吞掉异常try{// 代码}catch(IOExceptione){// 什么都不做}// 3. 捕获后立即抛出try{// 代码}catch(IOExceptione){throwe;// 没有意义}// 4. 不恰当的使用运行时异常publicvoidreadFile(Stringpath){// 文件操作应该使用编译时异常thrownewRuntimeException("文件读取失败");}

总结

运行时异常

  • 用途:表示编程错误和逻辑错误
  • 处理:可选,通常通过代码检查避免
  • 例子:NullPointerException, IllegalArgumentException
  • 原则:快速失败,暴露问题

编译时异常

  • 用途:表示外部环境问题和可恢复错误
  • 处理:必须处理,强制调用者关注
  • 例子:IOException, SQLException
  • 原则:优雅处理,提供恢复机制

理解这两种异常的区别有助于编写更健壮、更易维护的 Java 代码。运行时异常用于快速发现编程错误,编译时异常用于处理外部环境的不确定性。

http://www.jsqmd.com/news/403327/

相关文章:

  • 光伏阵列常见故障仿真模型附Simulink仿真
  • 根脉与花开:AI元人文——***文化思想在智能时代的原创性理论发展
  • 什么是 Java 中的自动装箱和拆箱?
  • 光伏储能直流系统MATLAB仿真(PV光伏阵列+Boost DCDC变换器+负载+双向DCDC变换器+锂离子电池系统)附Matlab代码
  • 基于1D-GAN生成对抗网络的数据生成方法研究附Matlab代码
  • 什么是 Java 中的迭代器(Iterator)?
  • 光储直流微电网附Simulink仿真
  • 什么是 Java 的网络编程?
  • 【开题答辩全过程】以 高校学生档案管理系统为例,包含答辩的问题和答案
  • 大模型搜索引爆营销新赛道,智跑AI以GEO系统引领智能获客潮流
  • Java 中的基本数据类型有哪些?
  • 基于ARIMA-CNN-LSTM预测模型研究附Python代码
  • D证-科目一
  • 官网-劳动人事争议仲裁办案规则
  • Java 的 I/O 流是什么?
  • 航天器交会的分布式MPC模型预测控制研究附Matlab代码
  • Java 的 Optional 类是什么?它有什么用?
  • 如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?
  • 图论——最短路Dijkstra算法
  • 2026年保健品推荐:品质与口碑并存,养胃颗粒/保健饮品/保健品,保健品品牌有哪些 - 品牌推荐师
  • [NOI2018] 冒泡排序
  • 通过MATLAB控制COMSOL Multiphysisc仿真进程模拟局部放电,建立有限元仿真模型
  • 【GLM-5 陪练式前端新手入门】第四篇:卡片布局 —— 让个人主页内容更有层次
  • Splay进阶
  • 【GLM-5 陪练式前端新手入门】第三篇:网页导航栏 —— 搭建个人主页的 “指路牌”
  • [AI提效-17]-豆包图片生成功能新手入门指南
  • 写一个自动检测照片光线构图,给出优化建议,颠覆拍照全靠盲拍。
  • Python基于Vue的 古城景区管理系统的设计与实现django flask pycharm
  • 视频孪生平台之上:镜像视界三维实时解算体系在危化园区风险半径动态解算中的全球领先性研究
  • 2134523