异常的概念
任何的异常都是Throwable类(为何不是接口??),并且在它之下包含两个字类Error / Exception,而Error仅在当在Java虚拟机中发生动态连接失败或其它的定位失败的时候,Java虚拟机抛出一个Error对象。典型的简易程序不捕获或抛出Errors对象,你可能永远不会遇到需要实例化Error的应用,那就让我们关心一下Exception。
Exception中比较重要的就是RuntimeException(运行时异常)-可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明,也就是说你的应用应该不去“关心”(说不关心是不服责任的,但只是你不应该试图实例化它的字类)。 RuntimeException,就如同你不应该关心Error的产生与处理一样!RuntimeException描述的是程序的错误引起来的,因该由程序负担这个责任!(从责任这个角度看Error属于JVM需要负担的责任;RuntimeException是程序应该负担的责任;checked exception 是具体应用负担的责任)
除了Error与RuntimeException,其他剩下的异常都是你需要关心的,而这些异常类统称为Checked Exception,至于Error与RuntimeException则被统称为Unchecked Exception.
关于 Java 中引入的 Checked Exceptions,目前存在着很多反对意见。正方的观点是引入 Checked Exceptions,可以增加程度的鲁棒性。反方的观点是 Checked Exceptions 很少被开发人员正确使用过,并且降低了程序开发的生产率和代码的执行效率。
Java 中定义了两类异常:
1) Checked exception: 这类异常都是Exception的子类 。异常的向上抛出机制进行处理,如果子类可能产生A异常,那么在父类中也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。C#中就没有使用这种异常机制。
2) Unchecked exception: 这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是特殊的,它们不能通过client code来试图解决,所以称为Unchecked exception。
(JAVA视线论坛robbin's view,个人觉得用来做业务流程控制违背了Exception设计的初衷,但可以借鉴一下)
在使用UseCase来描述一个场景的时候,有一个主事件流和n个异常流。异常流可能发生在主事件流的过程,而try语句里面实现的是主事件流,而catch里面实现的是异常流,在这里Exception不代表程序出现了异常或者错误,Exception只是面向对象化的业务逻辑控制方法。如果没有明白这一点,那么我认为并没有真正明白应该怎么使用Java来正确的编程。
而我自己写的程序,会自定义大量的Exception类,所有这些Exception类都不意味着程序出现了异常或者错误,只是代表非主事件流的发生的,用来进行那些分支流程的流程控制的。例如你往权限系统中增加一个用户,应该定义1个异常类,UserExistedException,抛出这个异常不代表你插入动作失败,只说明你碰到一个分支流程,留待后面的catch中来处理这个分支流程。传统的程序员会写一个if else来处理,而一个合格的OOP程序员应该有意识的使用try catch 方式来区分主事件流和n个分支流程的处理,通过try catch,而不是if else来从代码上把不同的事件流隔离开来进行分别的代码撰写。
(另外一种观点,不同于robbin,个人赞同,并引用于此)
1。什么时候抛出异常--涉及到服务类
2。抛出checked还是unchecked的异常--涉及到客户类
对第一个问题来说,我想异常本身这个字解释了某些东西,异常就是我们认为在正常情况下不可能发生的问题,并且服务代码不知道如何去处理。譬如说我做一个监控程序,需要用压缩卡提供的API去初始化所有的板卡,API提供的是boolean型的返回值,但我把这个API变成抛出一个异常,因为除非特殊原因,我不认为会发生初始化失败的情况,当然更不知道怎样去处理这个问题。又譬如Hibernate里面的LoadObject使用没有发现这个对象存在,那Hibernate也是认为不可能的,除非其他代码直接删除了数据库里面的记录,那么也需要抛出异常。当然Hibernate本身也不知道如何处理这种情况。
但是如果发生的情况是可以预期的,那我不认为应该抛出例外。象上面这个userExist的情况,我认为应该在前面已经分流,应该首先判断这个用户是否存在,if(userExists()),然后进行处理,而不应当抛出例外。以及login应当返回true或者false。也就是说,这些属于程序的正常流程,而不是例外,不是异常。把例外作为正常程序流程的控制机制,只不过是把服务代码中的if转移到客户代码去,没有减少任何需要处理的代码,反而增加了系统的负担(生成例外栈)。
还有抛出异常的情况是违反方法的先决条件,每一个方法都有自己的先决条件和后置条件,方法只有在正确的前提下才能执行达到一个正确的后果,(所谓类的不变量)。譬如你去存取一个数组的某一个元素,这个存取方法有一个前提条件,就是你的索引应当落入它的最大下标和最小下标之间,不然就应当抛出一个例外。
对于第二个问题,端视于客户代码是否能够根据这个例外进行合理的处理。如果客户代码根本就不知道如何处理这个例外,应当把它作为一个unchecked例外,例如上面下标的问题,客户代码用一个不合法的下标来存取数组,那么抛出一个checked例外以后,客户代码是+1还是-1?显然根本就不可能做出“合理的”处理,客户既然不能处理,还要强制它去处理,那么就是捕获,打印了事,没有增加任何价值。但是如果是客户可以处理的,或者可以选择不同的方式处理的,那么就可能需要用checked,但我发现很少有这样的情况。对于类似于RemoteException或者SQLException这些Exception,我一般都转换为具体的业务Exception,而我所有的业务Exception都是RuntimeException.
所以我的观点是,是否抛出例外就是服务代码是否进行合理的处理,抛出什么类型的例外就是客户代码是否能够合理的处理。
保护封装性的代码实例:
不要让你要抛出的checked exception升级到较高的层次。例如,不要让SQLException延伸到业务层。业务层并不需要(不关心?)SQLException。你有两种方法来解决这种问题:
1)转变SQLException为另外一个checked exception,如果客户端并不需要恢复这种异常的话;
2)转变SQLException为一个unchecked exception,如果客户端对这种异常无能为力的话;
多数情况下,客户端代码都是对SQLException无能为力的,因此你要毫不犹豫的把它转变为一个unchecked exception,看看下边的代码:
public void dataAccessCode(){
try{
. .some code that throws SQLException
}catch(SQLException ex){
ex.printStacktrace();
}
}
上边的catch块紧紧打印异常信息而没有任何的直接操作,这是情有可原的,因为对于SQLException你还奢望客户端做些什么呢?(但是显然这种就象什么事情都没发生一样的做法是不可取的)那么有没有另外一种更加可行的方法呢? 看下面代码:
public void dataAccessCode(){
try{
..some code that throws SQLException
}catch(SQLException ex){
throw new RuntimeException(ex);
}
}
上边的做法是把SQLException转换为RuntimeException,一旦SQLException被抛出,那么程序将抛出RuntimeException,此时程序被挂起并返回客户端异常信息。 调用该方法的程序代码中也不用再捕获SQLException异常:
public void do(){
dataAccessCode();
}
分享到:
相关推荐
在C#编程语言中,`checked`和`unchecked`是两个关键字,用于处理整数类型运算时可能出现的溢出情况。...而在性能至关重要的场合,或者确信运算不会溢出的情况下,可以使用`unchecked`以避免不必要的异常处理开销。
- 何时使用checked和unchecked上下文? 6. **垃圾回收(GC)** - 垃圾回收的基本原理和过程。 - 如何影响和优化GC的行为? - 理解内存分配的堆和栈。 7. **ADO.NET与数据库交互** - SqlConnection、...
- 异常的分类:讲述了Checked异常和Unchecked异常的区别,以及何时使用try-catch-finally结构。 - 自定义异常:如何创建自己的异常类,以及何时抛出异常。 5. **多线程编程** - 线程的创建:讲解了通过Thread类...
- **异常处理**:熟悉Java异常处理机制,能够区分checked异常和unchecked异常,并能正确编写try-catch-finally语句块来处理异常。 - **面向对象特性**:理解封装、继承、多态的概念,能够运用这些特性来设计类和接口...
书中将介绍如何正确地使用try-catch-finally语句块来捕获和处理异常,理解Checked异常和Unchecked异常的区别,以及如何自定义异常。 Java反射API允许程序在运行时动态地获取类的信息并操作对象,这在许多场合非常...
- 异常体系:熟悉Checked异常与Unchecked异常的区别。 - try-catch-finally:理解异常处理的结构,finally块的执行逻辑。 - 自定义异常:如何创建并抛出自定义异常。 4. **内存管理与垃圾回收** - 堆与栈:了解...
理解如何使用try-catch-finally语句块,以及何时使用checked异常和unchecked异常,能够避免程序在运行时因未捕获异常而崩溃。 2. **内存管理**:Java通过垃圾回收机制自动管理内存,但开发者仍需理解对象生命周期和...
5. **异常处理**:掌握try-catch-finally的使用,理解checked异常和unchecked异常的区别,以及自定义异常的创建。 6. **IO流**:理解字节流和字符流,以及缓冲流、转换流、对象流的使用。了解NIO(非阻塞I/O)在高...
- **异常分类**:理解Checked异常和Unchecked异常的区别。 - **try-catch-finally**:掌握异常处理的基本结构。 - **throw与throws**:理解它们在抛出异常时的差异。 - **自定义异常**:如何创建并使用自定义...
掌握Java的异常层次结构,辨别checked exception和unchecked exception。 能够分别创建新的异常类,检测抛出异常和捕获处理异常。 认识常见的异常及出现场景。 [*]知道开启和使用断言机制...
Java的异常处理机制分为两类:受检异常(Checked Exceptions)和非受检异常(Unchecked Exceptions)。受检异常通常是由应用程序逻辑错误引起的,必须被捕获或声明抛出。非受检异常,也称为运行时异常,通常由系统...
Java中的异常机制及CheckedException与UncheckedException - **异常处理机制**: - Java通过异常处理机制来处理程序中的错误,包括抛出异常、捕获异常和处理异常。 - **CheckedException**: - 需要在方法签名中...
- 运行时异常( unchecked exceptions)在编译时不强制处理,通常表示编程错误,如空指针异常。一般异常(checked exceptions)在编译时必须处理,通常表示预期外但可以恢复的情况。 6. **Servlet生命周期与CGI的...