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

认识异常详解

1. 异常的定义:

在Java中,异常(Exception)是在程序执行过程中可能出现的错误或意外情况。异常可以分为两种类型:受检异常(Checked Exception)未受检异常(Unchecked Exception)

所谓异常,就是一个一个的类,他们之间存在着父子类关系,如下图所示:

2. 异常的分类: 

  1. 受检异常(Checked Exception)

    • 受检异常是指在编译时必须进行处理的异常。它们是 Exception 的子类(不包括 RuntimeException 和其子类),通常表示程序能够合理预料和处理的情况,如文件未找到、网络连接中断等。
    • 受检异常必须通过 try-catch 块或者在方法签名中使用 throws 关键字声明,否则编译器将报错。
  2. 未受检异常(Unchecked Exception)

    • 未受检异常也称为运行时异常(RuntimeException)及其子类。它们通常表示程序运行时出现的错误,如空指针异常(NullPointerException)、数组越界异常(ArrayIndexOutOfBoundsException)等。
    • 未受检异常不要求显式地捕获或者声明,因为它们通常是由程序逻辑错误引起的,应该在代码中避免。

 受检异常:

特点和处理方式

  1. 必须处理或声明

    • 受检异常必须在代码中显式处理,否则编译器将会报错。这是Java编译器强制执行的规定,以保证程序在可能出现问题的地方有预防措施。
  2. 常见的受检异常

    • IOException:处理输入输出流时可能抛出的异常,如文件未找到、文件读写错误等。
    • SQLException:操作数据库时可能抛出的异常。
    • ClassNotFoundException:试图加载类时找不到该类时抛出的异常。
    • FileNotFoundException:尝试打开一个不存在的文件时抛出的异常。
  3. 异常处理方式

    a. 使用 try-catch 块

try {// 可能抛出受检异常的代码块FileReader file = new FileReader("file.txt");// 其他可能抛出异常的操作
} catch (FileNotFoundException e) {// 处理异常的代码e.printStackTrace();
} catch (IOException e) {// 处理其他IO异常的代码e.printStackTrace();
}

 

  • 在 try 块中放置可能抛出异常的代码,每个 catch 块用于捕获不同类型的异常,并在捕获到异常后执行相应的处理逻辑。

b. 使用 throws 关键字抛出异常

  • 方法签名中使用 throws 关键字声明方法可能抛出的受检异常。这样做可以将异常向上层调用者传递,由调用者处理。
public void readFile() throws IOException, FileNotFoundException {FileReader file = new FileReader("file.txt");// 其他可能抛出异常的操作
}
    • 调用 readFile() 方法时,调用者必须要么在其内部使用 try-catch 块处理异常,要么在其方法签名中继续向上抛出异常。
  1. 适用场景

    • 当方法中有可能出现会影响程序正常运行的情况时,应该使用受检异常。这种异常通常要求程序员预见可能的问题,并在代码中进行相应的处理,以保证程序的稳定性和可靠性。
  2. 最佳实践

    • 在处理受检异常时,建议不仅仅是简单地打印堆栈信息,而是根据具体情况采取适当的措施,比如向用户报告错误、进行重试、回滚操作等,以便尽可能地恢复正常的程序执行状态。

未受检异常:

特点和处理方式

  1. 不需要显式处理或声明

    • Java编译器不会强制要求在代码中捕获或声明未受检异常,这使得程序员在处理逻辑上更加灵活,但也需要注意避免因未捕获的异常导致程序意外终止。
  2. 常见的未受检异常

    • NullPointerException:当引用为空(null)时尝试调用其方法或访问其属性时抛出。
    • ArrayIndexOutOfBoundsException:尝试访问数组中不存在的索引位置时抛出。
    • ArithmeticException:数学运算异常,如除以零。
    • IllegalArgumentException:方法接收到非法参数时抛出。
    • ClassCastException:类型转换异常,在类型转换时发生类型不兼容时抛出。
  3. 异常处理方式

    • 尽管未受检异常不要求强制处理,但好的编程实践是在可能引发这些异常的地方进行适当的逻辑检查,以避免程序出现异常状态。
    • 如果未捕获的未受检异常发生,通常会导致程序异常终止,并打印异常堆栈信息,这可以帮助定位问题所在。
  4. 适用场景

    • 未受检异常通常表示程序员在代码逻辑中出现了错误或者未能预料到的情况。例如,当方法要求传入的参数为非空时却接收到了空值,可以抛出 NullPointerException。这种异常通常需要通过改进代码逻辑来避免,而不是依赖于异常处理机制。
  5. 最佳实践

    • 在编写代码时,应该注意对可能导致未受检异常的情况进行检查和预防,尽量避免程序运行时因为这类异常而意外终止。
    • 对于可能引发未受检异常的方法,可以通过文档、注释或者断言等手段来说明其预期的使用条件,以便其他开发人员正确使用。

3. 异常的处理:

捕获异常(try-catch)

  • 使用 try 块包裹可能会引发异常的代码,然后通过 catch 块捕获特定类型的异常并处理它们。
try {// 可能抛出异常的代码块int result = 10 / 0; // 这里会抛出 ArithmeticException
} catch (ArithmeticException e) {// 处理算术异常的代码System.out.println("除数不能为零");
} catch (Exception e) {// 捕获其他类型的异常e.printStackTrace();
}
  • try 块中的代码在执行时,如果抛出了 ArithmeticException 异常(例如除以零),程序会跳到对应的 catch 块中执行处理逻辑。

 

抛出异常(throw)

  • 当方法内部无法处理某些异常情况时,可以使用 throw 关键字显式地抛出异常对象,将异常传递给调用者处理。
public void withdraw(double amount) throws InsufficientFundsException {if (amount > balance) {throw new InsufficientFundsException("余额不足");}// 执行取款操作balance -= amount;
}
  • 在上述例子中,如果取款金额大于账户余额,则抛出自定义的 InsufficientFundsException 异常。

  • 使用 finally 块

    FileInputStream file = null;
    try {file = new FileInputStream("file.txt");// 读取文件
    } catch (FileNotFoundException e) {e.printStackTrace();
    } finally {// 关闭文件流,确保资源得到释放if (file != null) {try {file.close();} catch (IOException e) {e.printStackTrace();}}
    }

  • finally 块用于执行无论是否发生异常都需要执行的代码,比如资源释放操作(如关闭文件、数据库连接等)。

使用 try-with-resources(Java 7+):

  • 当需要处理的资源实现了 AutoCloseable 或 Closeable 接口时,可以使用 try-with-resources 语句自动关闭资源。
try (FileInputStream file = new FileInputStream("file.txt")) {// 读取文件
} catch (IOException e) {e.printStackTrace();
}
  • 在 try 后面的括号中声明资源,程序结束时会自动调用其 close() 方法,无需手动关闭资源。

异常处理的最佳实践

  • 选择合适的异常处理方式:根据具体情况选择 try-catchthrowfinally 或 try-with-resources 等方式。
  • 准确捕获异常:捕获尽可能具体的异常类型,避免过于宽泛的 catch (Exception e) 形式。
  • 避免捕获过多:尽可能在能够预见和处理异常的地方捕获和处理,而不是在整个应用程序的最高层捕获所有异常。
  • 异常信息的处理:合理利用异常信息提供的堆栈信息,帮助调试和定位问题。
  • 保持代码清晰:异常处理应与正常逻辑分开,保持代码的清晰和可读性。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 01背包问题-队列分支限界法-C++
  • 数据结构之“栈”(全方位认识)
  • C++初学者指南-4.诊断---基础:警告和测试
  • 宿舍报修小程序的设计
  • 从入门到深入,Docker新手学习教程
  • 网络-calico问题分析
  • Java面试八股之MySQL存储货币数据,用什么类型合适
  • 24.6.30
  • C++笔试强训2
  • c_各个unsigned int 和 int的取值范围
  • Exploting an API endpoiint using documentation
  • 011 多线程问题
  • 【刷题汇总--大数加法、 链表相加(二)、大数乘法】
  • 在原有的iconfont.css文件中加入新的字体图标
  • 【OnlyOffice】桌面应用编辑器,插件开发大赛,等你来挑战
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Asm.js的简单介绍
  • emacs初体验
  • es6(二):字符串的扩展
  • Gradle 5.0 正式版发布
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • node和express搭建代理服务器(源码)
  • 两列自适应布局方案整理
  • 聊聊redis的数据结构的应用
  • 码农张的Bug人生 - 见面之礼
  • 前端js -- this指向总结。
  • 体验javascript之美-第五课 匿名函数自执行和闭包是一回事儿吗?
  • AI算硅基生命吗,为什么?
  • zabbix3.2监控linux磁盘IO
  • 湖北分布式智能数据采集方法有哪些?
  • ​1:1公有云能力整体输出,腾讯云“七剑”下云端
  • # 达梦数据库知识点
  • ###C语言程序设计-----C语言学习(3)#
  • #数据结构 笔记一
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • $$$$GB2312-80区位编码表$$$$
  • (2)MFC+openGL单文档框架glFrame
  • (k8s)kubernetes集群基于Containerd部署
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (黑马C++)L06 重载与继承
  • (三十五)大数据实战——Superset可视化平台搭建
  • (十六)一篇文章学会Java的常用API
  • (一)认识微服务
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .net oracle 连接超时_Mysql连接数据库异常汇总【必收藏】
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET多线程执行函数
  • .stream().map与.stream().flatMap的使用
  • @EnableConfigurationProperties注解使用
  • @ModelAttribute使用详解
  • []使用 Tortoise SVN 创建 Externals 外部引用目录
  • [BZOJ5125]小Q的书架(决策单调性+分治DP+树状数组)
  • [HDCTF 2023]Welcome To HDCTF 2023