Java编程中的检查型异常与非检查型异常分析

发布时间 - 2026-01-11 03:10:15    点击率:

        对于因为编程错误而导致的异常,或者是不能期望程序捕获的异常(解除引用一个空指针,数组越界,除零,等等),为了使开发人员免于处理这些异常,一些异常被命名为非检查型异常(即那些继承自 RuntimeException 的异常)并且不需要进行声明。

Checked Exception和Unchecked Exception的几点不同之处
        方法签名是否需要声明exception,调用该方法时是否需要捕获exception,exception产生的时候JVM控制程序的状态。

Sun 的“The Java Tutorial”观点
        因为 Java 语言并不要求方法捕获或者指定运行时异常,因此编写只抛出运行时异常的代码或者使得他们的所有异常子类都继承自RuntimeException ,对于程序员来说是有吸引力的。这些编程捷径都允许程序员编写 Java 代码而不会受到来自编译器的所有挑剔性错误的干扰,并且不用去指定或者捕获任何异常。尽管对于程序员来说这似乎比较方便,但是它回避了 Java 的捕获或者指定要求的意图,并且对于那些使用您提供的类的程序员可能会导致问题。

        检查型异常代表关于一个合法指定的请求的操作的有用信息,调用者可能已经对该操作没有控制,并且调用者需要得到有关的通知 —— 例如,文件系统已满,或者远端已经关闭连接,或者访问权限不允许该动作。

        如果您仅仅是因为不想指定异常而抛出一个 RuntimeException ,或者创建RuntimeException 的一个子类,那么您换取到了什么呢?您只是获得了抛出一个异常而不用您指定这样做的能力。换句话说,这是一种用于避免文档化方法所能抛出的异常的方式。在什么时候这是有益的?也就是说,在什么时候避免注明一个方法的行为是有益的?答案是“几乎从不。”

        换句话说,Sun 告诉我们检查型异常应该是准则。该教程通过多种方式继续说明,通常应该抛出异常,而不是 RuntimeException —— 除非您是 JVM。

        在 Effective Java: Programming Language Guide一书中(请参阅参考资料),Josh Bloch 提供了下列关于检查型和非检查型异常的知识点,这些与 “The Java Tutorial” 中的建议相一致(但是并不完全严格一致):

第 39 条:只为异常条件使用异常。也就是说,不要为控制流使用异常,比如,在调用 Iterator.next() 时而不是在第一次检查Iterator.hasNext() 时捕获NoSuchElementException 。

第 40 条:为可恢复的条件使用检查型异常,为编程错误使用运行时异常。这里,Bloch 回应传统的 Sun 观点 —— 运行时异常应该只是用于指示编程错误,例如违反前置条件。

第 41 条:避免不必要的使用检查型异常。换句话说,对于调用者不可能从其中恢复的情形,或者惟一可以预见的响应将是程序退出,则不要使用检查型异常。

第 43 条:抛出与抽象相适应的异常。换句话说,一个方法所抛出的异常应该在一个抽象层次上定义,该抽象层次与该方法做什么相一致,而不一定与方法的底层实现细节相一致。例如,一个从文件、数据库或者 JNDI 装载资源的方法在不能找到资源时,应该抛出某种ResourceNotFound 异常(通常使用异常链来保存隐含的原因),而不是更底层的IOException 、SQLException 或者NamingException 。

一、Java中异常概述

1.1Java异常结构

        Throwable可以用来表示任何可以被作为异常抛出的类。Throwable对象派生出两种类型:Error和Exception,前者用来表示编译时和系统错误,程序员往往不必关心;后者是可以被抛出的基本类型,需要程序员关注。RuntimeException是Exception的派生类,不同点将在2.2与2.3小结中描述。

       Java的异常(Exception)按照编译器检查方式又可以分为检查型异常(CheckedException)和非检查型异常(UncheckedException)。

1.2检查型异常(CheckedException)

        在Java中所有不是RuntimeException派生的Exception都是检查型异常。当函数中存在抛出检查型异常的操作时该函数的函数声明中必须包含throws语句。调用改函数的函数也必须对该异常进行处理,如不进行处理则必须在调用函数上声明throws语句。

        检查型异常是JAVA首创的,在编译期对异常的处理有强制性的要求。在JDK代码中大量的异常属于检查型异常,包括IOException,SQLException等等。

1.3非检查型异常(UncheckedException) 

       在Java中所有RuntimeException的派生类都是非检查型异常,与检查型异常相对抛出非检查型异常可以不在函数声明中添加throws语句,调用函数上也不需要强制处理。

        常见的NullPointException,ClassCastException是常见的非检查型异常。非检查型异常 可以不使用try...catch进行处理,但是如果有异常产生,则异常将由JVM进行处理。对于RuntimeException的子类最好也使用异常处理机制。虽然RuntimeException的异常可以不使用try...catch进行处理,但是如果一旦发生异常,则肯定会导致程序中断执行,所以,为了保证程序再出错后依然可以执行,在开发代码时最好使用try...catch的异常处理机制进行处理。

1.4异常的关键字

        Java异常处理涉及到五个关键字,分别是:try、catch、finally、throw、throws

        五个关键字的相关语法略。

二、异常处理方式

2.1异常链

        在JDK1.4以后版本中,Throwable类支持异常链机制。Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。最后,它还可以包含 cause(原因):另一个导致此 throwable 抛出的 throwable。它也称为异常链 设施,因为 cause 自身也会有 cause,依此类推,就形成了异常链,每个异常都是由另一个异常引起的。

        通俗的说,异常链就是把原始的异常包装为新的异常类,并在新的异常类中封装了原始异常类,这样做的目的在于找到异常的根本原因。

2.2异常的转译

        异常转译就是将一种异常转换另一种新的异常并且再抛出的过程,异常转译的目的是将系统中出现的不同类型的异常进行型别的统一,以便于异常的统一处理。
绝大多数情况下转译出的“结果异常”类型都是自定义异常,并且在异常转译过程中需要将“原始异常”放置在异常链中。

2.3自定义异常

        自定义异常就是自写的继承了Exception或RuntimeException的异常类。实现自定义异常的目的大致可分为以下三种:

        1.使用统一的类型标识多种不同型别的异常。

        2.在产生异常时更好的进行信息传递。常见的手段是在异常中定义异常码,异常信息,环境对象等字段。

        3.将检查型异常转换为非检查型异常。

三异常处理

3.1关于检查型异常与非检查型异常的争论

        在实际编程过程中使用检查型异常与非检查型异常的时机从JAVA语言产生的那一天开始就已经产生。

        最为官方的说法可以参考Java最核心设计者之一JOSHUA BLOCH的《Effective Java》异常使用章节,他的主张是:对可恢复的情况使用检查型异常,对编程错误使用运行时异常。

        虽然上述说法有着“皇家血统”但事实上在我看来Java的检查型异常是一个非常失败的作品,因为检查型异常具有超强的“污染性”,它的出现所带来的麻烦远比好处要多得多。我的观点是:几乎在所有的情况下都不应当使用检查型异常。当遇到检查型异常无法处理的情况时,应该使用异常转译转换为非检查型异常再抛出。我非常兴奋的看到在Think in Java 4th Edition上作者对这样的观点进行了详细的描述。

        Java创造检查型异常的初衷是在编译期强制程序员对异常情况进行处理,从而使得程序更加的强壮可靠,可是Java的作者忘记了:好的程序设计语言能帮助程序员写出好程序,但无论那种语言都避免不了程序员用它写出坏程序。

        对于异常处理的关键点并不在于是在编译期还是运行期对异常进行检查,而在于异常一定要检查并且需要建立统一的、一致的异常检查与处理模型。

3.2我的异常处理原则

        1.仅处理当前可处理的异常。

        2.对所有的检查型异常使用异常转译。

        3.所有的自定义异常都是非检查型异常。

        4.异常流程与正常流程进行分离,并尽可能的统一处理。

        5.在非异常处理模块的catch块中尽可能不记日志。

        6.除非是进行资源释放操作,否则catch块不应为空或者出现e.printTrace

        7.finally块中不能出现复杂的操作,且不可以抛出异常,也不可以出现return。

3.3我处理异常的一般方式

        1.将throw语句视为异常流程的起点,将Exception对象视作正常流程向异常流程跃迁过程中的数据载体。

        2.建立统一的自定义异常类型,用以包装所有检查型异常。

        3.大多数情况下仅在程序的主干上建立唯一的异常捕获点,并在这个点上对接收到的异常进行处理。

总结

以上是本文的全部内容,希望对大家有所帮助。


# java  # 检查型异常  # 非检查型异常  # 谈谈RxJava2中的异常及处理方法  # JAVA抛出异常的三种形式详解  # 使用IDEA异常断点来定位java.lang.ArrayStoreException的问题  # Java如何将处理完异常之后的程序能够从抛出异常的地点向下执行?  # Mybatis单个参数的if判断报异常There is no getter for property  # 利用Java8 Optional如何避免空指针异常详解  # java.lang.ExceptionInInitializerError异常的解决方法  # Java 异常java.lang.NoSuchFieldException解决方案  # 抛出  # 自定义  # 是在  # 子类  # 都是  # 过程中  # 不需要  # 什么时候  # 并在  # 情况下  # 这样做  # 它还  # 转换为  # 调用者  # 与非  # 而不是  # 这是  # 也就是说  # 可恢复  # 他们的 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel怎么清理缓存_Laravel optimize clear命令详解  详解Nginx + Tomcat 反向代理 负载均衡 集群 部署指南  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法  佛山网站制作系统,佛山企业变更地址网上办理步骤?  Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南  PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)  新三国志曹操传主线渭水交兵攻略  Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】  详解jQuery中的事件  如何正确选择百度移动适配建站域名?  JavaScript中的标签模板是什么_它如何扩展字符串功能  如何用PHP快速搭建高效网站?分步指南  phpredis提高消息队列的实时性方法(推荐)  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程  如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?  如何快速搭建支持数据库操作的智能建站平台?  Laravel广播系统如何实现实时通信_Laravel Reverb与WebSockets实战教程  Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】  网站建设保证美观性,需要考虑的几点问题!  合肥制作网站的公司有哪些,合肥聚美网络科技有限公司介绍?  Claude怎样写约束型提示词_Claude约束提示词写法【教程】  武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?  Win11关机界面怎么改_Win11自定义关机画面设置【工具】  百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏  Java解压缩zip - 解压缩多个文件或文件夹实例  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  千库网官网入口推荐 千库网设计创意平台入口  如何在IIS管理器中快速创建并配置网站?  Laravel如何实现URL美化Slug功能_Laravel使用eloquent-sluggable生成别名【方法】  javascript如何操作浏览器历史记录_怎样实现无刷新导航  Win11怎么设置虚拟桌面 Win11新建多桌面切换操作【技巧】  图册素材网站设计制作软件,图册的导出方式有几种?  在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?  如何在宝塔面板创建新站点?  HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】  Laravel如何升级到最新版本?(升级指南和步骤)  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  详解CentOS6.5 安装 MySQL5.1.71的方法  高防服务器如何保障网站安全无虞?  手机软键盘弹出时影响布局的解决方法  如何在香港服务器上快速搭建免备案网站?  Laravel Octane如何提升性能_使用Laravel Octane加速你的应用  Laravel如何处理JSON字段的查询和更新_Laravel JSON列操作与查询技巧  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  如何快速选择适合个人网站的云服务器配置?  Laravel Docker环境搭建教程_Laravel Sail使用指南  Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】  Android okhttputils现在进度显示实例代码  香港服务器租用每月最低只需15元?