JAVA异常处理

异常处理机制

异常处理机制可以使程序中的异常处理代码和正常业务代码分离。
多个catch块之后可以跟一个finally,finally块用于回收try块里打开的物理资源,异常机制会保证finally块总是被执行。
JAVA提出一种假设,如果程序顺利完成,则一切正常,把系统的业务实现代码放在try块中,把所有的异常处理逻辑放在catch块中进行处理。

JAVA运行时环境(JRE)收到异常对象时,会寻找能处理该异常的catch块,如果找到了合适的catch块,就将该异常对象交给该catch块处理,这个过程被称为捕获(catch)异常;如果JAVA运行时环境找不到捕获异常的catch块,那么运行时环境将终止,JAVA程序也将退出。

不管程序代码是否位于try块中,甚至包括catch块中的代码,只要执行该代码块时出现了异常,系统总会自动生成一个异常对象。如果没有为这个异常定义任何catch块,那么运行时环境无法找到处理该异常的catch块,程序就此退出。

每个catch块都是专门用于处理该异常类及其子类的异常实例,try块之后可以有多个catch块,但try执行一次,最多有一个catch块运行,绝不可能有多个catch块运行。

JAVA中非正常情况分为Exception和Error两种,Error错误,一般是指和虚拟机有关的问题——系统崩溃,虚拟机崩溃,动态链接失败等,这类错误无法被捕获或者修复,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该用catch块来捕获Error对象。

当试图调用一个null对象的实例方法或实例变量时,就会引发NullPointerException异常。
在异常捕获时,一定要先捕获小异常,后捕获大异常。

从JAVA7开始,一个catch块可以捕获多种类型的异常,多种类型异常之间用竖线(|)分开,多种异常的异常变量有隐式的final修饰,因此程序不能为异常变量重新赋值。

当Java运行时决定调用某个catch块来处理该异常对象时,会将异常对象赋值给catch块的异常参数,程序即可通过该参数来获得异常的相关信息。

finally块

不管try中有没有异常,不管哪个catch块被执行,甚至在try块或catch块中执行了return,finally块总会被执行。

如果没有try块,则后面不能出现catch块和finally块。但如果出现try块,则catch块和finally块必须出现一个。多个catch块必须位于try块之后,finally块必须位于所有catch块之后。

return语句会强制方法结束,但一定会先执行finally块代码,如果将return 改为System.exit(1)语句退出虚拟机,则finally块将失去执行的机会。
不要在finally块使用return、throw等会导致方法终止的语句,一旦在finally块中使用这些语句,会导致try,catch块中的return、throw语句失效。
public class FinallyFloatTest {
		public static void main(String []args)throws Exception
		{
			boolean a=test();
			System.out.println(a);
		}
		public static boolean test()
		{
			try
			{
				return true;
			}
			finally
			{
				return false;
			}
		}
}
运行结果是false,也就是,try块中的return语句失效了。

JAVA7中指定关闭资源的try语句

JAVA7增强了try语句功能——允许try关键字后紧跟一对圆括号(不再是大括号),圆括号中可以声明并初始化一个或多个资源,这里的资源指的是那些必须在程序结束时显示关闭的资源(如数据库连接,网络连接),try语句结束后这些资源将自动关闭,

为了保证try语句可以正常关闭资源,这些资源必须实现AutoCloseable或Closeable语句,实现这两个接口就必须实现close()方法。

自动关闭资源的try语句等于自带finally块,所以其后面可以不加catch块和finally块。

Checked异常和Runtime异常体系

Checked异常是JAVA特有的。JAVA认为Checked异常都是可以被处理(修复)的异常,所以JAVA程序必须显示处理Checked异常,如果程序没有处理Checked异常,该程序在编译时就会发生错误,无法通过编译。
而Runtime异常更为灵活,无需显式抛出,如果程序需要捕获Runtime异常,也可以使用try catch来实现。

throws声明抛出的思路是——当前方法不知道该如何处理该类型的异常,该异常就应该有上一级的调用者处理,如果主函数也不知道该如何处理,也可以使用throws声明抛出异常,将该异常传给JVM来处理。JVM对异常的处理方式是打印异常跟踪栈的信息,并终止程序运行。

throws可以抛出多个异常类,异常类之间以逗号隔开

如果某一段代码中调用了一个带throws声明的方法,那么表面该程序希望其调用者处理这个异常,该方法要么放在一个try块中,要么放在另一个带有throws异常的方法里。

子类方法声明抛出的异常类型应与父类声明抛出的异常类型相同(或者是其子类),子类抛出的异常不允许比父类声明抛出的异常多

在方法中显式声明Checked异常会导致该方法签名与异常耦合,若该方法是重写父类的方法,那么该方法抛出的异常还受父类异常的限制。

当使用Runtime一次时,程序无需在方法中声明Checked异常,一旦发生自定义异常,直接抛出即可。
如果程序需要在合适的地方捕获并处理异常,使用try catch语句即可。

使用throw抛出异常

throw语句抛出的不是一个异常类,而是一个异常实例,而且每次只能抛出一个异常实例。

如果throw语句抛出的是Checked异常,那么该throw语句要么处于try块中,要么处于一个带throws声明的方法中;如果throw抛出的是Runtime异常,那么无需放在try块中,也无需放在带throws声明的方法中——程序可以显示地使用try catch语句捕获该异常,也可以完全不理会该异常,将该异常交给方法调用者来处理。

用户自定义异常都应该继承自Exception类,如果希望自定义Runtime异常,这应该继承RuntimeException基类。定义异常时通常需要提供两个构造器:一个无参构造器;另一个是带字符串的构造器——该字符串作为异常的描述信息(也就是异常对象getMessage()方法的返回值)
public class AuctionException extends Exception{
	public AuctionException()
	{}
	public AuctionException(String str)
	{
		super(str);
	}

}
如上述代码所示,通过super()方法可以将字符串参数传给异常对象的message属性,该message属性就是该异常对象的详细描述信息。

异常类名应该能准确的描述异常类型。

实际使用异常机制时,一个方法可以只处理部分异常,然后将异常再次抛出,让方法的调用者处理剩余的异常(catch语句块中再抛出异常)


从JAVA7开始编译器会进行细致的检查——编译器会检查throw语句抛出的异常的实际类型,因此可以抛出更准确的异常,而不是像之前那样粗暴的抛出。

把一个异常捕获然后抛出另一个异常,并把原始异常信息保留下来是一种典型的链式处理(23种设计模式之一:职责链模式),也被称为异常链。
从JDK1.4之后,Throwable基类有了一个可以接受Exception参数的方法,所以可以使用以下代码:
public class SalException extends Exception {
	public SalException(){}
	public SalException(String msg)
	{
		super(msg);
	}
	public SalException(Throwable t)
	{
		super(t);
	}

}<strong>
</strong>

JAVA的异常跟踪栈

根据printStackTrace()方法输出结果,开发者可以找到异常的源头,并跟踪到异常一路触发的过程。
打印信息的顺序是——最开始触发异常的地方,然后异常向外传播,传给了该方法的调用者...最后一只传到main方法。如果main方法也没有处理该异常,那么JVM会终止该程序,并打印异常的跟踪栈信息。

第一行信息详细显示了异常的类型和异常的详细消息,然后是跟踪栈记录程序中所有的异常发生的位置,显示被调用方法中执行终止的位置,并标明类、类中的方法名、与故障点对应的文件的行。

异常处理规则

不要过度使用异常

对于普通错误,应书写处理错误的代码,只有对外部的、不可确定、不可预知的运行时错误才使用异常。
异常机制的效率要低于正常的流程控制效率,所以不要使用异常处理来替代正常的程序流程控制。

不要使用过于庞大的try块

应该吧大块的try分割成多个可能出现异常的程序段落,并把它们放在单独的try块中,分别捕获和处理。

不要忽略捕获到的异常

捕获到异常后应该处理并修复这个异常,catch块不要为空,也不要仅仅是打印该异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值