检查型异常和非检查型异常

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

Checked Exception和Unchecked Exception的几点不同之处

  • 方法签名是否需要声明exception
  • 调用该方法时是否需要捕获exception
  • exception产生的时候JVM控制程序的状态

Sun 的“The JavaTutorial”观点

因为 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.       大多数情况下仅在程序的主干上建立唯一的异常捕获点,并在这个点上对接收到的异常进行处理。

时间: 2024-10-24 11:19:43

检查型异常和非检查型异常的相关文章

【Java】检查型异常和非检查型异常

检查型异常(CheckedException)在Java中所有不是RuntimeException派生的Exception都是检查型异常.当函数中存在抛出检查型异常的操作时该函数的函数声明中必须包含throws语句.调用改函数的函数也必须对该异常进行处理,如不进行处理则必须在调用函数上声明throws语句. 检查型异常是JAVA首创的,在编译期对异常的处理有强制性的要求.在JDK代码中大量的异常属于检查型异常,包括IOException,SQLException等等. 非检查型异常(Unchec

对检查性异常和非检查性异常的理解

从开始学习Java,就学习了异常处理,知道异常分为检查性异常和非检查性异常,RuntimeException属于非检查性异常,知道异常的分类.但工作之前没有很多的实际应用,知识书本上课件上的定义,对两种异常的理解并不是很清楚.工作后在实际代码中,逐渐捋顺清楚了,这里记录一下,基础知识就不说了,书上课件上网上资料很丰富,这里只总结对两种异常的理解. 1.检查性异常: JAVA编译器强制要求用try{}catch(){}块进行处理,如果不处理则必须在包含可能发生异常的代码的方法上用throws显示地

Java运行时异常和非运行时异常

1.Java异常机制 Java把异常当做对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类.Java中的异常分为两大类:错误Error和异常Exception,Java异常体系结构如下图所示: 图片来源:http://blog.csdn.net/wuwenxiang91322/article/details/10346337 2.Throwable Throwable类是所有异常或错误的超类,它有两个子类:Error和Exception,分别表示错误和异常.其中异

Java检查型异常和非检查型异常

1.代码 public class ExcepTest { /** * @param args */ public static void main(String[] args) { System.err.println("111111111111"); // say(); //抛出异常,但是代码不显示的try..catch.. // calc(); //抛出异常,但是代码不显示的try..catch.. // try { // show(); // } catch (Exceptio

根据数字型样式或非数字型样式创建文件夹

2018-10-31 17:14:17  开始写 数字型 非数字型 1 import javax.swing.JFrame; 2 import javax.swing.JPanel; 3 import javax.swing.border.EmptyBorder; 4 import javax.swing.JLabel; 5 import javax.swing.JOptionPane; 6 7 import java.awt.Font; 8 import javax.swing.JTextFi

使用JFileChooser实现在指定文件夹下批量添加根据“数字型样式”或“非数字型样式”命令的文件夹

2018-11-05 20:57:00开始写 Folder.java类 1 import javax.swing.JFrame; 2 import javax.swing.JPanel; 3 import javax.swing.border.EmptyBorder; 4 import javax.swing.JLabel; 5 import javax.swing.JOptionPane; 6 7 import java.awt.Font; 8 import javax.swing.JText

java 检查异常 和 非检查异常

个人见解 ,如果有问题 ,还希望大神们 指正 1. 非检查异常 又称运行时 异常 ,所有 继承自 RuntimeException 的异常都是 非检查异常  ,, 如果你不处理  会有 虚拟机 main  方法处理 2. 凡是 不继承自 RuntimeException 的异常都是 检查异常 (如 IO 异常) 3. 上层调用者必须对  检查 异常 做处理 : try_catch  或者 继续 throws 给上层处理 4.  为什么要有检查异常: 通常情况下 ,检查异常 并不是你的程序写的有问

运行时异常和非运行时异常

RunntimeException的子类: ClassCastException 多态中,可以使用Instanceof 判断,进行规避 ArithmeticException 进行if判断,如果除数为0,进行return NullPointerException 进行if判断,是否为null ArrayIndexOutOfBoundsException 使用数组length属性,避免越界 这些异常时可以通过程序员的良好编程习惯进行避免的 1:遇到运行时异常无需进行处理,直接找到出现问题的代码,进

运行时异常和非运行是异常

Throwable是所有Java程序中错误处理的父类,有两种资类:Error和Exception. Error:表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息. Exception:表示可恢复的例外,这是可捕捉到的. Java提供了两类主要的异常:runtime exception和checked exception.checked 异常也就是我们经常遇到的IO异常,以及SQL异