20190111——第十二章 通过异常处理错误

本文深入探讨Java异常处理机制,解释其基本理念与目的,包括错误恢复、异常捕获与处理,以及自定义异常的创建。文章阐述了异常处理如何简化大型程序的错误管理,提高代码的可读性和维护性。

Java的基本理念是“结构不佳的代码不能运行”

发现错误的理想时机是在编译阶段,也就是你在试图运行程序之前,然后,编译期间,并不能找出所有的错误,余下的问题必须在运行期间解决,这就需要错误源能通过某种方式,把适当的信息传递给某个接收者——该接受者将知道如何正确处理这个问题。

改进的错误恢复机制是提供代码健壮性的最强有力的方式,错误恢复在我们所编写的每一个程序中都是基本的要素,要想创建健壮的系统,它的每一个构件都必须是健壮的。java使用异常来提供一致的错误报告模型,使得构件能够与客户端代码可靠地沟通问题,

java中的异常处理的目的在于通过使用少于目前数量的代码来简化大型、可靠的程序的生成。

因为异常处理是Java中唯一正式的错误报告机制,并且通过编译器强制执行,所以不学习异常处理的话,本章,将向读者介绍如何编写正确的异常处理程序,并将展示出方法出问题的时候,如何产生自定义的异常。

概念
“异常”这个词有我感到意外的意思,问题出现了,你也许不清楚该如何处理,但你的确知道不应该置之不理,你要停下来,看看是不是有别人或在别的地方,能够处理这个问题,只是在当前的环境中,你还没有足够的信息来解决这个问题,所以就把这个问题提交到一个更高级别的环境,在这里将作出正确的决定。

使用异常所带来的另一个相当明显的好处是,它往往能够降低错误处理代码的复杂度,如果不使用异常,那么就必须检查特定的错误,并在程序中的许多地方去处理它,而如果使用异常,那么就不必在方法调用处检查,因为异常机制将保证能够捕获这个错误,并且,只需要在一个地方来处理错误,即所谓的异常处理程序中,这种方式不仅节省代码,而且把 “描述在正常执行过程中做什么事”的代码和“出了问题怎么办”的代码相隔离,总之,与以前的错误处理方法相比,异常的机制使代码的阅读,编写和调试工作更加显得井井有条

基本异常
是指阻止当前方法或作用域继续执行的问题。把异常问题与普通问题区分很重要,所谓的普通问题是在当前的环境下能得到的足够信息,总能处理这个问题。而对于异常情形,就不能继续下去了,因为在当前环境下无法或得必要的信息来解决问题,你所能做的就是从当前环境跳出,并且把问题交给上一级环境,就是抛出异常所发生的事情。

当抛出异常的时候,有几件事随之发生,首先,同Java其他对象的创建一样,将使用new在堆上创建对象。然后,当前的执行路径,(它不能再继续下去了)被终止,并且从当前环境中弹出异常对象的引用,此时,异常处理机制接管程序,并开始寻找一个恰当的地方来执行程序,这个恰当的地方就是异常处理程序,它的任务就是将程序从错误状态中恢复,以使程序能要么换一种方式运行,要么继续运行下去。

举一个抛出异常的列子,对于引用对象t,传给你的时候可能尚未被初始化,所以在使用这个对象引用调用方法之前,会先对其进行检查,可以创建一个代表错误信息的对象,并且将他从当前环境抛出,这样就把错误信息传播到了“更大”的环境中,这被称为抛出个异常,

捕获异常
要明白异常是如何被捕获的,必须首先理解监控区域的概念,它是一段可能产生异常的代码,并且后面跟着处理这些异常的代码。

try块
如果在方法内部抛出了异常(或者在方法内部调用的其他方法抛出了异常),这个方法将在抛出异常的过程中结束。要是不希望方法就此结束,可以在方法内设置一个特殊的块来捕捉异常,因为在这个块中,尝试各种(可能产生异常的)方法调用,所以称为try块,它是跟在try关键字之后的程序。

try{
	
}

对于不支持异常处理的程序语言,要想仔细的检查错误,就得在每个方法调用的前后加上设置和错误检查的代码,甚至在每次调用同一方法时也得这么做,有了异常处理机制,可以把所有的动作都放在try块中,然后只需在一个地方就可以捕获所有异常,这意味着代码将更容易编写和阅读,因为完成任务的代码没有与错误检查的代码混在一起。

异常处理程序
当然抛出异常必须在某处得到处理,这个地点就是异常处理程序,而且针对每个要捕获的异常,得准备相应的处理程序,异常处理程序紧跟在try块之后,以关键字catch表示

try{}
catch(){}

每个catch子句(异常处理程序)看起来就像接收一个且仅接收一个特殊类型的参数的方法,可以在处理程序的内部使用标识符(id1,id2),这与方法参数的使用很相似,有时候可能用不到标识符,因为异常的类型已经给了你足够的信息来对异常进行处理,但标识符并不可以省略。

异常处理程序必须紧跟在try块之后,当异常被抛出的时候,异常处理机制将负责搜寻参数与异常类型匹配的第一个处理程序,然后进行catch子块执行,此时认为异常得到了处理,一旦catch子句结束,则处理程序的查找过程结束,注意,只有匹配的catch的子句才能得到执行,这与switch语句不通,switch需要在每一个后面跟上一个break跳出循环,

注意在try块的内部,许多不同的方法调用可能会产生 类型相同的异常,而你只需要提供一个针对此类型的异常处理程序。

终止和恢复
异常处理理论上有两种基本模型,Java支持终止模型(它是Java和C++所支持的模型)在这种模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行,一旦异常被抛出,就表示错误已经无法挽回,也不能回来继续执行。

另一种称为恢复模型,意思是异常处理程序的工作是修正错误,然后重新尝试调出问题的方法,并认为第二次能成功,对于恢复模型,通常希望异常被处理之后就能继续执行这个程序,如果想要Java实现恢复的行为,那么在遇见错误时就不能抛出异常,而是调用方法来修正该错误,或者,把try块放在while循环中,这样就不断地进行try块,直到得到满意的结果。

创建自定义异常
不必拘泥于Java已有的异常类型,Java提供的异常体系不可能预见所有的希望加以报告的错误,所以可以自己定义异常类来表示程序中可能会遇到的特定问题。

要自己定义异常类,必须从已有的异常类继承,最好的方式选择意思相近的异常类继承(不过这样的异常几乎不好找)建立新的异常类型最简单的方法就是让编译器为你产生默认的构造器,所以这几乎不用写多少代码。

在异常处理程序中,调用了在Throwable类声明的printStackTrace()方法,就像输出中看到的,它将打印,“从方法调用处知道异常抛出处”的方法调用序列,这里,信息被发送到了System.out并自动地捕获和显示输出中,但是如果调用默认版本,则信息将会被输出到标准错误流

捕获所有异常
可以只写一个异常处理程序来捕获所有异常的,通过捕获异常类型的基类的Exception,就可以做到这一点,(事实上还有其他的基类,但是Execxception是同编程活动相关的基类)

catch(Exception e){
	sout("我捕捉到了异常")
}

这将捕获所有异常,所以最好把它放在处理程序列表的末尾,以防它抢在其他处理程序之前先把异常捕获了。
因为Exception是与编程有关的所有异常的基类,所以它不会含有太多具体的信息,不过可以调用它从基类Throwable继承的方法

finally
对于没有垃圾回收的析构函数自动调用机制的语言来说,finally非常重要,它能使程序员保证,无论try块发生了什么,内存总能得到释放,但Java有垃圾回收机制,所以内存的释放不是问题。而且。java也没有什么析构函数可供调用,那么java在什么情况中,才能用到finally呢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值