深度剖析JAVA异常处理机制

JAVA异常处理机制

什么是异常,异常的分类

异常机制既当程序出现错误时,应该怎样对错误进行处理的一种机制,在JAVA中,异常是采用类的方式来表现,RuntimeException异常类都在java.lang包下面,所以不需要我们import导入,下面用一张图片来表示异常类之间的继承关系。
在这里插入图片描述
所有异常类的父类都是Throwable类,Throwable有两个子类,既Error类和Exception类,Error类是指当java虚拟机出现错误时引发的异常,这种异常一般是比较严重的异常,是由于java虚拟机本身出现了错误,如堆内存不够用了之类的,这种错误是我们处理不了的,这里就不在详述。

而另一种Exception类,则是我们可以对其进行处理的异常。Exception也有两个子类,IOException和RuntimeException,RuntimeExcption是在程序运行阶段出现的错误,在编译时编译器并不能直接发现,如数组下标越界,传入空的引用,算数运算中的除0错误等,这类错误一般都是由于程序员在写代码时出现的纰漏,是人为原因造成的,这类异常我们可以不处理,也能编译通过,但在运行时出如果出现异常时jvm就会自动抛出异常,打印一个描述异常的字符串,打印异常发生处的堆栈轨迹停止程序的运行。

而如果对一些可能出现的异常进行捕获,我们就可以用我们自己的方式去处理这些异常,不让整个程序停止运行。比如我们进行除法运算时,如果除数是由键盘进行输入的,我们事先并不知道除数是0还是其他的数,这个时候我们为了防止程序出现除0异常而终止,我们就会有两种解决方案,一种是在进行除法运算之前进行if判断,如果输入的是0则不进行除法运算,既不给程序报错的机会。第二种就是使用try catch语句进行捕获,当出现除0错误后,在catch语句中进行处理。前一种方法是在程序报错之前进行处理,后一种则是在发出异常之后进行处理。

至于IOException,我们则必须使用throws语句抛出或者使用try catch 进行处理,否则会编译不通过。而这又是为什么呢,这是因为java是一门健壮性、可维护性高的语言,IO类等类在运行的时候很有可能会出现异常,比如在读取文件的时候可能会出现文件不存在的异常,为了保证java的健壮性和高可用性,高维护性等特性,java的一些IO类或者其他容易出现异常的类当中都使用了throws语句进行异常抛出,所以当我们使用这些类的方法的时候,我们也必须对其进行抛出或者捕获。如果父类的方法抛出了异常,子类不能抛出比父类更多的异常。

抛出异常,throws和throw

对异常的处理,我们可以对其进行抛出或者捕获,抛出异常既是将异常抛给上层的方法处理,如果上层的方法不处理的话也必须抛出,直到main函数,如果main函数中也没有进行捕获处理,那么在main函数中也必须抛出,既抛给jvm去处理,jvm就会用自己的默认方法区处理,既我在上面提到过的方法。所以对于运行时异常,我们要么就不处理,让jvm自己去处理,要么就使用try catch进行捕获处理,如果对于运行时异常我们也进行抛出,如果到了main函数中还是继续抛出的话,那是没有意义的,因为最终还是会让jvm进行处理,当然,对于运行时异常一般都是由于代码不严谨造成的,我们一般都是可以避免的,所以一个合格的程序员应该尽量不要让自己的代码出现运行时异常。而对于IOException,因为我们必须进行抛出或者捕获,所以如果我们不想对其进行处理的话,我们就既可以进行抛出,如果我们想自己处理的话,就可以捕获。
throw语句的目的是用来主动引发一个异常的实例,如果出现throw,那么我们就必须对其进行捕获或者抛出。而throws则是抛出一个异常类型给上层的方法,有这个类型的异常才会抛出。

public class TestException_2 {
	//调用了prin方法,必须将接收到的prin方法抛出的异常抛给java虚拟机或者使用try catch进行捕获
	public static void main (String args[]) throws Exception{
		
		int a = 10;
		int b = 1;
		
		int c = a/b;
		System.out.println(c);	
		prin();
	}
	//因为使用throw语句引发了异常,并且没有进行捕获,所以这里必须使用throws语句将异常抛给上层的main函数
	public static void prin() throws Exception{
	System.out.println("我将主动引发一个异常");
	Exception e = new Exception();//实例化一个异常e
	throw e;//引发这个异常
	}
}

运行结果:
在这里插入图片描述

这里的prin方法中引发了一个Exception异常,所以我们必须将其捕获或者抛出,否则编译不通过,抛出的意思其实就是提醒java虚拟机,我这个地方很可能会出现异常,需要你来处理这个异常

捕获异常,try catch finally语句

public class TestException1 {
	public static void main(String args[]) {
		
		int a = 10;
		int b = 0;
		//开始进行异常捕获
		try {
		int c = a/b;
		System.out.println(c);
		}
		//如果捕获到了ArithmeticException异常,则执行下面的语句
		catch(ArithmeticException e){
			System.out.println("当出现ArithmeticException异常时,我就会执行!");
			e.printStackTrace();			
		}
        //如果引发的不是ArithmeticException,则继续检测是不是RuntimeException,如果是,则会执行下面的语句
		catch(RuntimeException e){
			System.out.println("当出现RuntimeException异常时,我就会执行!");
			e.printStackTrace();			
		}
		//如果引发的不是RuntimeException,则会检测是不是Exception,如果是,则会执行下面的语句
		catch(Exception e){
			System.out.println("当出现Exception异常时,我就会执行!");
			e.printStackTrace();			
		}
		//不管是否有异常,都会执行,相当于是一个收尾工作
		finally {
			System.out.println("不管是否引发异常,我都会执行!");
		}
				
	}
}

运行结果:
在这里插入图片描述
如图所示,我将0赋给b,然后用a去除0,就会引发RuntimeException中的ArithmeticException,然后catch捕捉到了这个错误,所以就执行了其中的语句,而已经没捕捉到了,所以下面的catch语句就不会执行了,而finally中的语句还是会执行

这段代码是一个简单的try catch finally语句的应用,catch字句可以有一个,也可以有多个,catch语句的运行顺序是先运行上面的catch,如果catch到了,则下面的catch就不会执行了,所以当我们使用多个catch语句时,异常捕获的范围应该是由小到大,最后到Exception类,因为Exception类是所有我们可以进行处理的类的父类,所以只要引发了异常,如果上面都没捕获到的话,到这里一定会被捕获
至于finally,可以写也可以不写,finally中的代码不管是否引发异常都会被执行,如果try语句中有return语句,则finally中最好不要放return 语句,因为如果程序正常运行时,当finally语句中存放return语句时,return 回去的也是finally语句中的值,而不是原本想要返回的值。并且finally语句中放了return的话,后面就无法在执行其他语句了。

此外,try catch finally中定义的变量都是局部变量,作用域仅限于它们自己内部,比如我在try语句中定义了一个变量,那这个变量在catch和finally以及外部都无法使用

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值