您的位置:首页 > 编程语言 > Java开发

异常处理

2016-07-09 23:21 197 查看
Java把所有的非正常情况分成两种:异常和错误,它们都继承Throwable父类。Error错误,一般是指与虚拟机相关的问题,如系统崩溃等,这种错误无法恢复或不能捕获。异常是程序在运行时的不正常状态,一般是开发人员编译时造成的一般性错误。比如,将试图调用一个null对象的实例方法或实例变量时,就会引发空指针异常。在处理异常时,应该把所有父类异常的catch块都应该排在子类异常catch块的后面。否则,将会出现编译错误。异常捕获时,一定要记住先捕获小异常,再捕获大异常。

异常机制可以使得程序中的异常处理代码和正常业务代码分离,保证程序代码更加优雅,可以提高程序的健壮性和容错性。Catch后对应异常类型和一个代码块,简称try块,它里面可以放置引发异常的代码,多个catch后还可以跟一个finally块,用于回收在try块里打开的物理资源。异常机制保证finally块总是被执行。Java将异常分为两类,Checked异常和Runtime异常,checked异常都是可以在编译阶段被处理的异常,所以它强制程序处理所有的checked异常;而Runtime异常无需处理。 如果执行try块里的业务逻辑代码时出现异常,系统会自动生成一个异常对象,该异常对象被提交给Java运行时的环境,这个过程被称为抛出异常。当java运行时环境收到异常对象时,会寻找能处理该异常对象的catch块,如果找到合适的catch块,则把该异常对象交给该catch块处理,这个过程称为捕获异常;如果java运行时的环境找不到捕获该异常的catch块,则运行时的环境终止,java程序也将退出。当系统发生不同的意外情况时,系统会生成不同的异常对象,java运行时就会根据该异常对象所属的异常类来决定使用哪个catch块来处理该异常。在通常情况下,如果try块被执行一次,则try块后面只有一个catch块会被执行,绝不可能有多个catch块被执行。除非在循环中使用continue开始下一次循环。

有些时候,程序在try块里打开了一些物理资源(例如数据库连接,网络连接,和磁盘文件等),这些物理资源必须显示的被回收,finally块里被显示的回收。异常处理结构中try块是必须的,catch块和finally块至少出现其中之一。在异常处理的catch块里如果使用System.exit(1)语句来退出虚拟机,则后面的finally块将失去执行的机会。
注意:尽量避免在finally块里使用return 或者throw等导致方法终止的语句。

当前方法明确知道如何处理异常时,程序使用try-catch块来捕获异常,如果当前方法不知道如何处理种种异常,应该在定义方法时声明抛出该异常。使用throws声明抛出异常的思路是,当前方法不知道如何处理异常,该异常应该由上一级调用者处理;如果main方法也不知道该如何处理异常,也可以抛出异常交给JVM来处理。JVM处理异常的方法时,打印异常的跟踪栈信息,并终止程序运行,这就是前面程序在遇到异常后自动结束的原因。
如果某段代码中调用了一throws声明的方法,该方法声明抛出了Checked异常,则表明该方法希望他的调用者来处理异常,也就是说,调用该方法时要么放在try块中显示捕获该异常,要么放在另一个带throws声明抛出的方法中。使用throws声明抛出的异常类型的一个限制是:子类方法声明抛出的异常不允许比父类方法声明抛出的异常多,应该是父类异常类型的子类或者相同。
当使用Runtime异常时,程序无需在方法中声明抛出Checked异常,一旦程序发生了自定义错误,程序只管抛出Runtime异常即可。如果程序需要再合适的地方捕获异常并对异常进行处理,同样可以使用try-catch块来捕获Runtime异常。但checked异常也有优势,它能在编译阶段提醒程序员代码可能有错误,提醒程序员必须处理该异常。

当程序出现错误时,系统会自动抛出异常;java也允许程序自行抛出异常,使用throw语句来完成(没有后面的s);
很多时候,系统是否要抛出异常,可能要根据应用的业务需求来决定,如果程序中的数据执行与既定的业务需求不符合,这就是一种异常。必须要程序员来决定来抛出,系统无法抛出这种异常。如果需要程序自动抛出异常,则应该使用throw语句,throw语句抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例。
用户自定义异常类时都应该继承Exception基类或者runtimeException基类,定义异常类时通常需要提供两个构造器,一个无参数构造器,一个带一个字符串的构造器,这个字符串将作为该异常对象的描述信息。 企业级应用对于异常处理通常分成两个部分:(1)应用后台需要通过日志来记录异常发生的详细情况(2)应用还需要根据异常向应用使用者传递某种提示。在这种情况下,所有异常都需要两个方法共同完成,就必须将catch和throw结合使用。直接把底层的原始异常传给用户是一种不负责任的表现。通常的做法是:程序先捕获原始异常,然后抛出一个新的业务异常,新的业务异常中包含了对用户的提示信息,这种处理方法被称为异常转译。这种把原始信息隐藏起来,仅向上提供必要的异常提示信息的处理方式,可以保证底层异常不会扩散到表象层,可以避免向上暴露太多的细节,这符合面向对象封装的原则。不能滥用异常处理机制。对于完全已知的错误和普通的错误,应该编写处理这种错误的代码,增加程序的健壮性。只有对外部的,不确定的和预知的运行时错误才使用异常。必须指出的是:异常处理机制的初衷是将不可预期异常的处理代码和正常的业务逻辑处理代码相分离,因此绝不要使用异常处理来代替正常的业务逻辑。另外,异常机制的的效率比正常的流程控制效率差,所以不要用异常处理来代替正常的程序流程控制。异常只是处理非正常的情况。注意:不要使用过于庞大的try块;正确的做法是,把大块的try块分割成多个可能出现异常的程序段落,并把他们放在单独的try块中,从而分别捕获处理异常。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java 异常