异常处理机制(基于Java)

一、什么是异常?

异常的英文单词是exception,字面翻译就是“意外、例外”的意思,也就是非正常情况。事实上,异常本质上是程序上的错误,包括程序逻辑错误和系统错误。比如使用空的引用、数组下标越界、内存溢出错误等,这些都是意外的情况,背离我们程序本身的意图。错误在我们编写程序的过程中会经常发生,包括编译期间和运行期间的错误,在编译期间出现的错误有编译器帮助我们一起修正,然而运行期间的错误便不是编译器力所能及了,并且运行期间的错误往往是难以预料的。
  Java 异常强制用户考虑程序的
强健性
安全性异常处理不应用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应处理
  异常就是java通过面向对象的思想将不正常情况封装成了对象,用异常类对其进行描述。

二、异常的处理机制

为什么要自定义自己的Exception ,Java Exception机制与传统的C语言的异常处理机制有什么不同,这种Exception机制的意义在什么地方?
  早期的C语言的异常处理机制,通常是我们人为的对返回结果加一些标志来进行判定,比如发生错误返回什么标志,正常情况下我们又是返回什么标记,而这些都不是语言本身所赋予我们的,而对于C语言这种机制又有什么问题哩?为什么新一代的语言 Java Ruby C# 等都用Exception机制而不是维持C语言的老样子?这些都是我们需要思考的问题。
  C语言的异常处理机制全是我们人为的定义,这样就会造成业务逻辑的主线受到异常处理的牵制,或者说是我们难免会将注意力转移,并且造成业务逻辑与异常处理之间有很大程度上的缠绕。
  
2.1 中止模型
  假设错误非常严重,已至你无法在回到错误发生的地方,也就是说,这段程序经过判断认为,他已经没有办法挽回,于是就抛出异常,希望这个异常不要在回来,这也是Java 当前所采用的模式。
  
2.2 继续模型
  这种模型的主旨是恢复当前的运行环境,然后希望能够重新回到错误的发生地,并希望第二次的尝试能够获得成功,这种模型通常为操作系统所应用。

三、异常的优劣

3.1 优点
  让异常处理与业务逻辑的主线分离,我们可以对可以遇见的异常作分支处理,其实将业务逻辑与异常处理分离也是Exception设计的主旨,其次Java Exception 不需要像C语言那样在程序的多个地方去检测同一个错误,并就地作异常的处理,相比老式的错误处理,现行的错误处理的结构则来的更加清晰
  异常机制主要提高了程序的强健性和安全性。
  
3.2 缺点
  (1)当一个方法中被过多的抛出受控异常,那么在别人调用的时候会造成try/catch语句的泛滥,甚至经常出现嵌套异常,使得代码的可读性下降。
  (2)在某些方面检测系统的异常也并没有实际的意义,因为当出现这种异常的时候一般代表问题很严重我们无法恢复,如:捕获数据库SQLException异常,该异常对我们来说没太大意义,因为错误信息太模糊,通常都是一些堆栈上的信息,看Rod Johnson 设计的关于JDBC方面的Exception Framework相信会对您产生很大的触动。
  (3)在大型系统中受控异常同时会造成异常处理类的泛滥,其实本人并没有介入过什么大型的Java 系统的设计工作,所以我也无从对这指三道四,没有实践就没有发言权,但我在一般的系统已经多少看到了一些这样的问题。

四、异常产生的原因和使用规则

4.1 产生原因
  (1)Java 内部错误发生异常,Java 虚拟机产生的异常。
  (2)编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。这种异常称为未检査的异常,一般需要在某些类中集中处理这些异常。
  (3)通过 throw 语句手动生成的异常,这种异常称为检査的异常,一般用来告知该方法的调用者一些必要的信息。
  
4.2 使用规则
编写代码处理某个方法可能出现的异常,可遵循如下三个原则:
  (1)在当前方法声明中使用 try catch 语句捕获异常。
  (2)一个方法被覆盖时,覆盖它的方法必须拋出相同的异常或异常的子类。
  (3)如果父类抛出多个异常,则覆盖方法必须拋出那些异常的一个子集,而不能拋出新异常。

4.3 Java如何操作异常
  Java 通过面向对象的方法来处理异常。在一个方法的运行过程中,如果发生了异常,则这个方法会产生代表该异常的一个对象,并把它交给运行时的系统,运行时系统寻找相应的代码来处理这一异常。
  我们把生成异常对象,并把它提交给运行时系统的过程称为
拋出(throw)异常
。运行时系统在方法的调用栈中查找,直到找到能够处理该类型异常的对象,这一个过程称为捕获(catch)异常
  Java 异常强制用户考虑程序的强健性安全性。异常处理不应用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应处理

五、异常分类

Throwable 类是 Java 语言中所有错误或异常的超类。它的两个子类是Error和Exception。
5.1 Exception(异常)
5.1.1 描述
  Exception是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。
  
5.1.2 继承关系
java.lang.Object
  java.lang.Throwable
    java.lang.Exception
    
5.1.3 特点
(1)可以是可被控制(checked) 或不可控制的(unchecked)
(2)表示一个由程序员导致的错误
(3)应该在应用程序级被处理

5.1.4 unchecked exception(非检查异常)和checked exception(检查异常,编译异常)
(1)unchecked exception(非检查异常)
  这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是非凡的,它们不能通过client code来试图解决,所以称为Unchecked exception 。也称运行时异常(RuntimeException),比如常见的NullPointerException、IndexOutOfBoundsException。对于运行时异常,java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。
(2)checked exception(检查异常,编译异常)
  这类异常都是Exception的子类 。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。也称非运行时异常(运行时异常以外的异常就是非运行时异常),java编译器强制程序员必须进行捕获处理,比如常见的IOExeption和SQLException。对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过。

5.2 Error(错误)
5.2.1 描述
  Error是程序无法处理的错误,表示运行应用程序中较严重问题大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual
MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。

5.2.2 继承关系
java.lang.Object
   java.lang.Throwable
    java.lang.Error
    
5.2.3 特点
(1)总是不可控制的(unchecked)
(2)经常用来用于表示系统错误或低层资源的错误
(3)如何可能的话,应该在系统级被捕捉

六、异常捕获

来自https://www.cnblogs.com/baiqiantao/p/9159435.html
setUncaughtExceptionHandler
public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
设置该线程由于未捕获到异常而突然终止时调用的处理程序。
通过明确设置未捕获到的异常处理程序,线程可以完全控制它对未捕获到的异常作出响应的方式。
如果没有设置这样的处理程序,则该线程的 ThreadGroup 对象将充当其处理程序。
public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()
返回该线程由于未捕获到异常而突然终止时调用的处理程序。
如果该线程尚未明确设置未捕获到的异常处理程序,则返回该线程的 ThreadGroup 对象,除非该线程已经终止,在这种情况下,将返回 null。

setDefaultUncaughtExceptionHandler
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。
未捕获到的异常处理首先由线程控制,然后由线程的 ThreadGroup 对象控制,最后由未捕获到的默认异常处理程序控制。
如果线程不设置明确的未捕获到的异常处理程序,并且该线程的线程组(包括父线程组)未特别指定其 uncaughtException 方法,则将调用默认处理程序的 uncaughtException 方法。
通过设置未捕获到的默认异常处理程序,应用程序可以为那些已经接受系统提供的任何“默认”行为的线程改变未捕获到的异常处理方式(如记录到某一特定设备或文件)。
请注意,未捕获到的默认异常处理程序通常不应顺从该线程的 ThreadGroup 对象,因为这可能导致无限递归。
public static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
返回线程由于未捕获到异常而突然终止时调用的默认处理程序。如果返回值为 null,则没有默认处理程序。

UncaughtExceptionHandler 类
public static interface Thread.UncaughtExceptionHandler
所有已知实现类:ThreadGroup
当 Thread 因未捕获的异常而突然终止时,调用处理程序的接口。
当某一线程因未捕获的异常而即将终止时,Java 虚拟机将使用 Thread.getUncaughtExceptionHandler() 查询该线程以获得其 UncaughtExceptionHandler 的线程,并调用处理程序的 uncaughtException 方法,将线程和异常作为参数传递。
如果某一线程没有明确设置其 UncaughtExceptionHandler,则将它的 ThreadGroup 对象作为其 UncaughtExceptionHandler。如果 ThreadGroup 对象对处理异常没有什么特殊要求,那么它可以将调用转发给默认的未捕获异常处理程序。
void uncaughtException(Thread t, Throwable e)
当给定线程因给定的未捕获异常而终止时,调用该方法。
Java 虚拟机将忽略该方法抛出的任何异常。

七、编程语句

来自https://www.cnblogs.com/baiqiantao/p/9159435.html
7.1 try catch finally 语句
(1)try语句中若检测到异常(Throwable)会将相关的信息封装成异常对象,然后传递给catch,catch捕获到后对异常进行处理。
(2)try中是一个独立的代码块,在其中定义的变量只在该代码块中有效,如果要在try以外继续使用,需要在try外进行声明。
(3)try中如果可能会捕获到多个异常,那么应该(建议)有对应个数的catch进行针对性处理。
一个try对应多个catch语句时,后面的catch子句中的参数类型只能是前面catch字句中参数类型的同级或父类,而不能是子类,也不能是同一个类型。
(4)一个try对应多个catch语句时,若前面的catch子句中的参数类型和实际捕获到的异常类型一致,则只执行此catch语句,而不会再匹配或执行下面的catch字句。
(5)finally语句里通常用来关闭资源。比如:数据库资源,IO资源等。
(6)try语句如果被执行到,finally语句中的代码只有一种情况不会被执行,就是在之前执行了System.exit(0)。

7.2 子类在覆盖父类方法时
(1)子类的方法只能抛出父类的方法抛出的异常或者该异常的子类,而不能抛出该异常的父类或其他类型的异常
(2)如果父类的方法抛出多个异常,那么子类的该方法只能抛出父类该方法抛出的异常的子集
(3)如果父类的方法没有抛出异常,那么子类覆盖父类的该方法时也不能抛,如果有异常只能使用 try catch 语句

7.3 throw
(1)throw 语句用于抛出异常对象,一条 throw 语句只能抛出一个异常对象,throw 语句抛出的异常也可以被 try 语句捕获
(2)throw 语句之后不能再有其他语句,因为 throw 语句后面的代码是执行不到的。
(3)RuntimeException 以及其子类可以在函数中通过 throw 抛出而不用在函数上声明。

注意
Error可以catch吗? 可以catch了后做些其他处理吗?
   Error是可以catch的,而且也可以向常规Exception一样被处理,而且就算不捕捉的话也只是导致当前线程挂掉,其他线程还是可以正常运行,如果有需要的话捕捉Error之后也可以做些其他处理。但是Error是一种系统内部的错误,这种错误不像Exception一样是可能是程序和业务上的错误是可以恢复的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值