第1章 异常与异常处理(上)

本章主要讲解,什么是异常、Java 中的异常体系结构、如何处理异常、如何自定义异常以及异常链的相关知识

1 - 1:Java异常简介

异常简介:异常处理的作用、Java异常体系结构简介

处理异常:try-catch及try-catch-finally、抛出异常、自定义异常、异常链

异常:有异于常态,和正常情况不一样,有错误出现。

阻止当前方法或作用域,称之为异常。

异常好比说一家工厂,本来是正常生产,但突然原料用完了的异常情况,没人处理这个问题,这就出现了工人没法干活,损失客户,老板赔本。如果原料用完时,员工把这样的问题给上级反映,管理人员作出处理,让采购那边订购原料,跟客户说明情况,保证不耽误出货,最后拉闸断电关机器,把所有占用资源释放,老板的损失就会降到最低。

上面这样一说,就是说什么是异常、异常处理的作用和意义。我们来看一下Java中异常体系结构。

在Java中有一个类叫Throwable类,这是异常体系的总类,Java中所有不正常类都继承与它,Throwable主要有两个“儿子”,一个是Error类,一个是Exception类。一般我们很少接触Error这个类,它指的是系统错误,有VirtualMachineError(虚拟机错误)ThreadDeath(线程死锁),如果出现了Error类,程序完全无法运行了。我们来看Exception类,这个类出现代表着编码、环境、用户操作输入出现问题。Exception也有“儿子”,有RuntimeException(非检查异常)CheckException(检查异常)。能够引起运行时异常的情况有很多,就像引用了一个空对象的属性或方法,也可能是数组访问越界,又或是类型转换出错,也有可能是算术方面引起的异常:

Runtime(非检查异常):

NullPointerException(空指针异常),如:
String str = null;
System.out.println(str.length());

ArrayIndexOutOfBoundsException(数组下标越界异常),如:
int array = {1, 2, 3};
for(int i = 0; i <= 3; i++){
	System.out.println(array[i]);
}

ClassCastException(类型转换异常),如:
class Animal(){
	
}
class Dog extends Animal(){
	
}
class Cat extends Animal(){
	
}
public class Test(){
	public static void main(String[] args){
		Animal a1 = new Dog();
		Animal a2 = new Cat();
		Dog d1 = (Dog)a1;
		Dog d2 = (Dog)a2;
	}
}

ArithmeticException(算术异常),如:
int one = 12;
int two = 0;
System.one.println(one/two);

当然还会有其他异常,要列举会要好多时间。

运行时异常会有Java虚拟机自动抛出,自动捕获,运行时异常的出现大部分情况下说明代码本身有问题,应该从逻辑上改变代码。

再看CheckException(检查异常),比如IOException(文件不存在)、SQLException(链接错误)。

 

1 - 2:Java中使用try...catch...finally实现异常处理

在Java中,我们使用try...catch或try...catch...finally这样的语句块来捕获并处理异常,我们先来看try...catch语句块。

try{
	//一些会抛出异常的方法
}catch(Exception e){
	//处理该异常的代码块
}

如果try块中发生异常,就会中止执行程序,然后程序的控制权会交由控制块中的异常处理程序进行处理。catch块中的代码该怎么写,如何处理这个异常则是根据不同业务情景再去不同对待。比如可以发出一些警提示用户或编程人员去检查一些配置、网络连接,也可以在catch中进行错误日志地记录等,就像下面代码:

try{
	System.out.print("请输入你的年龄:");
	Scanner input = new Scanner(System.in);
	int age = input.nextInt();
	System.out.println("十年后你" + (age + 10) + 岁);
}catch(InputMismatchException e){
	System.out.println("你应该输入整数!");
}
System.out.print("程序结束");

在try块中,首先提示用户输入年龄,通过Scanner对象去尝试捕获从键盘上输入的整数,如果我们输入的不是整数,就会抛出输入不匹配的异常,这个就会被系统捕获进入catch中,输出你应该输入整数。

注意,在try...catch块执行完后在catch块外面的其他语句会顺序的继续执行,最后无论怎样,程序结束都会显示在屏幕上。

如果try抛出很多异常,对于不同异常我们的处理方法不尽相同。如果所有类型异常都用catch块处理,那这个处理就会变得含糊不清,就相当于没有处理了。这时候我们就用到了多重catch块的语法:

try{
	//一些会抛出异常的方法
}catch(Exception e){
	//处理该异常的代码块
}catch(Exception e){
	//处理该异常的代码块
}

来康康这个:

Scanner input = new Scanner(System.in);
try{
	System.out.print("请输入第一个数:");
	int one = input.nextInt();
	System.out.print("请输入第二个数:");
	int two = input.nextInt();
	System.out.println("两数相除结果为:" + (one/two));
}catch(InputMismatchException e){
	System.out.println("你应该输入整数!");
}catch(ArithmeticException e){
	System.out.println("除数不能为0");
}catch(Exception e){
	System.out.println("我是不知名异常");
}
System.out.println("程序结束");

在try块后面用多个catc块来捕获异常,对其进行相应处理,上面在try块中定义了两个整形变量,one和two,它们都取自键盘上输入的整数值,这时候如果咱们输入第一个“one”的时候,我输入hello,就会抛出输入不匹配异常,程序就会输出你应该输入整数。在输入“two”的时候我们输入了0,程序里就会显示除数不能为0的字样。

写try...catch块注意事项:顺序问题。要按照先小后大,就是先子类后父类的顺序来编写多重catch语句块。因为当程序抛出异常的时候,异常处理系统会就近寻找匹配的处理异常程序,而子类继承于父类,针对于父类的异常处理程序对于子类也是适用的。上面的Exception e是上面异常的父类,所以要把针对于Exception的catc块放到最后。当然如果这个多重catch块顺序写错了,编译器在编译的时候也不会通过,会报错,

我们在写完try...catch语句之后也要做一些善后工作,比如关闭连接、或关闭一些已经打开的文件。而这种善后工作我们就在大括号后面加上finall语句块来进行善后。

try{
	//一些会抛出异常的方法
}catch(Exception e){
	//处理该异常的代码块
}catch(Exception2 e){
	//处理该异常的代码块
}finally{
	//最终要执行的代码
}

 

1 - 3:Java中通过案例学习fry...catch...finally

打开eclipse,建立imooc_exception_demo项目,在src创建个类,放在com.imooc.test包下,叫TryCatchTest类,自动生成main方法:

创建一个test方法,返回int类型值,先暂时让它返回0以免编译器报错。

这个test方法要先给他创建两个变量:divider(除数)、result(结果),try-catch用来捕获while循环,每次循环divider减一,result=result+100/result,如果捕获异常,打印输出抛出异常了,返回-1,否则返回result:

然后我们在main方法里调用一下这个方法了,先建一个try-catch的实例,名字为tct,建立一个int变量叫result接受tct的Task值,然后打印:

package com.imooc.test;

public class TryCatchTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TryCatchTest tct = new TryCatchTest();
		int result = tct.Test();
		System.out.println("test()方法执行完毕,返回值是" + result);
	}
	
	public int Test() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return -1;
		}
	}
}


/*结果:
java.lang.ArithmeticException: / by zero
	at com.imooc.test.TryCatchTest.Test(TryCatchTest.java:18)
	at com.imooc.test.TryCatchTest.main(TryCatchTest.java:8)
循环抛出异常了
test()方法执行完毕,返回值是-1
*/

确实,Test方法抛出了个异常,这个异常被catch语句块捕获,然后发现并在第18行中显示。

我们再写一个Test2方法,Test2方法和Test方法功能一样,但我们在Test2后面要加一个finally语句块,我们在finally中输出这是finally,哈哈,再输出result值。

package com.imooc.test;

public class TryCatchTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TryCatchTest tct = new TryCatchTest();
		int result = tct.Test2();
		System.out.println("test2()方法执行完毕");
	}
	
	public int Test() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return -1;
		}
	}
	
	public int Test2() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return result = 999;
		}finally {
			System.out.println("这是finally,哈哈");
			System.out.println("我是result,值是" + result);
		}
	}
}

/*结果:
java.lang.ArithmeticException: / by zero
	at com.imooc.test.TryCatchTest.Test2(TryCatchTest.java:34)
	at com.imooc.test.TryCatchTest.main(TryCatchTest.java:8)
循环抛出异常了
这是finally,哈哈
我是result,值是999
test2()方法执行完毕
*/

这里可以看到,在Test2抛出算术异常后,被catch语句块捕获,在方法返回到main方法之前,try调用了finally中的语句,输出了这是finally,哈哈,然后输出我是result,值是999,然后回到main方法。刚才我们讲到了try-catch-finally语句块中的语句和语句块之外的语句的执行顺序的问题,我们再改一下这个方法。我们把result等于999删去,在最后返回1111作为结果。

package com.imooc.test;

public class TryCatchTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		TryCatchTest tct = new TryCatchTest();
		int result = tct.Test3();
		System.out.println("test3()方法执行完毕,返回值为" + result);
	}
	
	public int Test() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return -1;
		}
	}
	
	public int Test2() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
			return result;
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
			return result = 999;
		}finally {
			System.out.println("这是finally,哈哈");
			System.out.println("我是result,值是" + result);
		}
	}
	
	public int Test3() {
		int divider = 10;
		int result = 100;
		try {
			while(divider > -1) {
				divider--;
				result = result + 100/divider;
			}
		}catch(Exception e) {
			e.printStackTrace();//这个方法显示抛出了什么异常
			System.out.println("循环抛出异常了");
		}finally {
			System.out.println("这是finally,哈哈");
			System.out.println("我是result,值是" + result);
		}
		System.out.println("我是test3,我运行完了!");
		return 1111;
	}
}

/*结果:
java.lang.ArithmeticException: / by zero
	at com.imooc.test.TryCatchTest.Test3(TryCatchTest.java:53)
	at com.imooc.test.TryCatchTest.main(TryCatchTest.java:8)
循环抛出异常了
这是finally,哈哈
我是result,值是381
我是test3,我运行完了!
test3()方法执行完毕,返回值为1111
*/

上面那个try块里的while算出来的结果是381,所以值是381。这里可以看出来,如果try-catch里面没有return语句,就会调用这三个语句块之外的语句。

 

1 - 4:练习题

下列关于 try-catch-finally 语句的描述中,错误的是( )

A、try 语句可以独立存在

B、catch 块跟在 try 语句后面,它可以是一个或多个

C、catch 块有一个参数,该参数是某种异常类的对象

D、多重 catch 语句中,异常类型必须子类在前父类在后

 

答案:A。解析:try 语句块不可以独立存在,必须与 catch 或者 finally 块同存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值