第8章异常处理

8.1 异常概述
在程序中,错误可能产生于程序员没有预料到的各种情况,或者是超出了程序员可控范围的环境因素,如试图打开一个根本不存在的文件等,在Java中,这种在程序运行时可能出现的一些错误称为异常。Java语言的异常处理机制优势之一就是可以将异常情况在方法调用中进行传递,通过传递可以将异常情况传递到合适的位置再进行处理

例8.1在项目由剑建米 Banll 在主方法中定义int型变量,将0作为除数赋值给该变量
40

package A;
public class Bault {//创建类Bault
	public static void main(String[] args) {//主方法
		int result=3/0;//定义int型变量
		System.out.println(result);//将变量输出
 
	}
 
}

8.2 异常的分类

8.2 异常的分类

Java类库的每个包中都定义了异常类,所有这些类都是Throwable类的子类。Throwable类派生了两个子类,分别是Error类和Exception类,其中,Error类及其子类用来描述Java运行系统中的内部错误以及资源耗尽的错误,这类错误比较严重。Exception类称为非致命性类,可以通过捕捉处理使程序继续执行。Exception 类又可以根据错误发生的原因分为运行时异常和非运行时异常。Java中的异常类继承体系如图8.2所示。

 8.2.1 系统错误——Error
Java运行系统中的内部错误,该类定义了常规环境下不的程序捕获的异常,比如OutOfMemoryError、ThreadDeath等,这些错误发生时,Java虚拟机(一般会选择线程终止。
例加 下面的代码在控制台中输出“梦想照亮现实”这句话,代码如下

package A;
 
public class Error {
	public static void main(String[] args) {
		System.out.println("梦想照亮现实!!!")//此处缺少必要分号
	}
}

  从图8.3的提示可以看到显示的异常信息为“java.lang.Error”,说明这是一个系统错误,程序遇到这种错误,通常都会停止执行,而且这类错误无法使用异常处理语句处理。

8.2.2 异常——Exception 

Exception是程序本身可以处理的异常,这种异常主要分为运行时异常和非运行时异常,程序中应当尽可能去处理这些异常,本节将分别对这两种异常进行讲解。

1.运行时异常 

运行时异常是程序运行过程中产生的异常,它是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
Java中提供了常见的RuntimeException异常,这些异常可通过try..catch语句捕获,如表8.1所示。

 

 例如,将一个字符串转换为整型,可以通过Integer 类的parselnt)方法来实现。如果该字符电不是数字形式,parseInt)方法就会显示异常,程序将在出现异常的位置终止,不再执行下面的语句。

例8.2 在项目中创建类Thundering,在主方法中实现将字符串转换为int型。运行程序,系统会报出异常提示。

package A;
public class Fhundering {
	public static void main(String[] args) {//主方法
		String str="lili";//定义字符串
		System.out.println(str+"年龄是:");//输出的字符串
		int age=Integer.parseInt("20L");//数据类型的转换
		System.out.println("age");//输出信息
	}
 
}

 

2.非运行时异常

非运行时异常是RuntimeException类及其子类异常以外的异常。从程序语法角度讲,这类异常是必须进行处理的异常,如果不处理,程序就不能编译通过,如1OExceprion、SQLExcepion以及用自定义的异常等。
Java中常见的非运行时异常类如表

 例 8.3 有一个名为“com.mrsoft”的足球队,现有队员为19名,现在要通过Clasfore("com.mrsoft.Coach")这条语句在Coach类中寻找球队的教练, 

public class FootabllTem {
	private int playNum;//定义"球员数量"
	private String temName;//定义球员名称
	public FootabllTem() {//构造方法Footablltem()
		Class.forName("com.mrsoft.Coach");//寻找教练类
	}
	public static void main(String[] args) {//创建对象tem
		FootabllTem tem=new FootabllTem();//初始化temName
		tem.temName="com.mrsoft";//初始化playerNum
		tem.playNum=19;
		System.out.println("\n球队名称:"+tem.temName+"\n"+"球员数量:"+tem.playNum+"名");
	}
 
}

 

 

package A;
 
public class FootabllTem {
	private int playNum;//定义"球员数量"
	private String temName;//定义球员名称
	public FootabllTem() {//构造方法Footablltem()
		try {
			Class.forName("com.mrsoft.Coach");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println("未找到相应异常");
		}//寻找教练类
	}
	public static void main(String[] args) {//创建对象tem
		FootabllTem tem=new FootabllTem();//初始化temName
		tem.temName="com.mrsoft";//初始化playerNum
		tem.playNum=19;
		System.out.println("\n球队名称:"+tem.temName+"\n"+"球员数量:"+tem.playNum+"名");
	}
 
}

 

 

 8.3捕捉处理异常
系统会自动为非运行时异常提供两种解决方案,一种是使用throws关键字,一种是使用try...catch代码块,这两种方法都是用来对异常进行处理的,本节首先对try...catch代码块进行讲解。
try..catch 代码块主要用来对异常进行捕捉并处理。在实际使用时,该代码块还有一个可选的finally代码块,其标准语法如下:

try{
//程序代码块
catch(Exceptiontype e){
//对Exceptiontype的处理
finally{
//代码块

}

块之后,用来激发被捕获的异常:finally代码块是异常处理结构的最后执行部分,无论程序是否发生异常,finally代码块中的代码都将执行,因此,在finally代码块中通常放置一些释放资源、关闭对象的代码。
通过try...catch代码块的语法可知,捕获处理异常分为try...catch代码块和finally代码块两部分,


 

package A;
 
public class FootabllTem {
	public static void main(String[] args) {//创建对象tem
	try {//try语句中包含可能出现异常程序代码
	String str="lili";//定义字符串变量
	System.out.println(str+"年龄是:");//输出的字符串
	int age=Integer.parseInt("20L");//数据类型的转换
	System.out.println("age");//输出信息
	}catch(NumberFormatException nfx){//捕捉 NumberFormatException异常
			nfx.printStackTrace();
	}catch(Exception e){// Exception异常
			e.printStackTrace();
	}
			System.out.println("program over");
			}
	}

  这时如果将两个 catch代码块的位置互换,即将捕捉Exception异常的 catch代码块放到捕捉NumberFormatException异常的catch代码块前面,

 

package A;
 
public class FootabllTem {
	public static void main(String[] args) {//创建对象tem
	try {
	String str="lili";//定义字符串
	System.out.println(str+"年龄是:");//输出的字符串
	int age=Integer.parseInt("20L");//数据类型的转换
	System.out.println("age");//输出信息
	
	}catch(Exception e){// Exception异常
			e.printStackTrace();
	}catch(NumberFormatException nfx){//捕捉 NumberFormatException异常
		nfx.printStackTrace();
}
			System.out.println("program over");
			}
	}

 例8.4 在项目中创建类 Take,在主方法中使用try...catch代码块将可能出现的异常语句进行异常处理

package A;
public class Take {//创建类
	public static void main(String[] args) {
			try {//try语句中包含可能出现异常的程序代码
		String str="lili";//定义字符串
		System.out.println(str+"年龄是:");//输出的字符串
		int age=Integer.parseInt("20L");//数据类型的转换
		System.out.println("age");//输出信息
	}catch(Exception e) {//catch代码块用来获取异常信息
		e.printStackTrace();//输出异常性质
	}
		System.out.println("program over");
	}
}

 

(1) getMessageO方法:获取有关异常事件的信息。
(2)toString方法:获取异常的类型与性质。
(3)printStackTrace0方法:获取异常事件发生时执行堆栈的内容。

注意:
有时为了编程简单会忽略catch代码块后的代码,这样try..catch语句就成了一种摆设,一旦程序在运行过程中出现了异常,就会导致最终运行结果与期望的不一致,而错误发生的原因很难查找。因此要养成良好的编程习惯,最好在catch代码块中写入处理异常的代码

8.3.2finally 代码块
完整的异常处理语句应该包含finally代码块,通常情况下,无论程序中有无异常发生,finally代码块中的代码都可以正常执行

例8.5 修改例8.4,将程序结束的提示信息放到finally代码块中

package A;
public class Take {
	public static void main(String[] args) {
		try {//try语句中包含可能出现异常的程序代码
		String str="lili";//定义字符串
		System.out.println(str+"年龄是:");//输出的字符串
		int age=Integer.parseInt("20L");//数据类型的转换
		System.out.println("age");//输出信息
	}catch(Exception e) {//catch代码块用来获取异常信息
		e.printStackTrace();//输出异常性质
	}finally {
		System.out.println("program over");
	}
		}
}


 

 

8.5自定义异常
Java中可以通过继承Exception类自定义异常类。
在程序中使用自定义异常类,大体可分为以下几个步骤。
(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try...catch代码块捕获并处理,否则,在方法的声明处通过throws关键字指明要抛给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。
有了自定义异常,再来解决年龄为负数的异常问题。

例8.8首先在项目中创建一个自定义异常类Exception,该类继承Exception

package A;
 
public class MyException extends Exception {//创建自定义异常,继承Exception类
	
	public MyException(String ErrorMessage) {//构造方法
		super(ErrorMessage);//父类构造方法
	}
 
	}

 在项目中创建类Tran,该类中创建一个带有int型参数的方法avg0,该方法用来检查年龄是否小于0,如果小于0,则使用throw关键字抛出一个自定义的MyException异常对象,并在 main()方法中捕捉该异常。代码如下:

package A;
 
public class Tran {
	//定义方法,抛出自定义的异常 判断方法中参数是否满好
	static void avg(int age) throws MyException{
	if(age<0) {//判断方法中参数是否满足指定条件
	throw new MyException("年龄不可以使用负数"); // 错误信息
	}else {
	System.out.println("王师傅今年 " + age+" 岁了!");
	}}
	
	public static void main(String[]args) { //主方法
	try { // try代码块处理可能出的代码
		avg(-50);
	
	}catch(MyException e) {
	e.printStackTrace();
			}
	}
}

 

                                       


   

                                         自定义异常主要用在以下场合。
(1)使异常信息更加具体,比如跟别人合作开发时,程序出现了空指针异常,但别人可能不清楚这个空指针是如何产生的,这时即可自定义一个显示具体信息的异常,比如自定义一个用户信息为空时抛出的异常:NullOfUserInfoException,当这个异常发生就代表用户填写的信息不完整。
(2)程序中有些错误是符合Java语法的,但不符合业务逻辑或者实际情况,比如程序中出现了一个人的年龄是负数、人员个数为小数等。
(3)在分层的软件架构中,通常在表现层统一对系统其他层次的异常进行捕获处理

 

8.6 异常的使用原则
Java异常强制用户去考虑程序的强健性和安全性。异常处理不应该用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应的处理。编写代码处理

异常时,可遵循以下原则。

异常时,可遵循以下原则。
(1)不要过度使用异常。虽然通过异常可以增强程序的健壮性,但如果使用过多不必要的异常处理,可能会影响程序的执行效率。
(2)不要使用过于庞大的try..catch块.在一个try块中放置大量的代码,这种写法看上去“很简单”,但是由于try块中的代码过于庞大,业务过于复杂,会造成try块中出现异常的可能性大大增加,从而导致分析异常原因的难度也大大增加。
(3)避免使用catch(Exception e)。因为如果所有异常都采用相同的处理方式,将导致无法对不同异常分情况处理;另外,这种捕获方式可能将程序中的全部错误、异常捕获到,这时如果出现一些“关键”异常,可能会被“悄悄地”忽略掉。
(4)不要忽略捕捉到的异常,遇到异常一定要及时处理。
(5)如果父类抛出多个异常,则覆盖方法必须抛出相同的异常或其异常的子类,不能抛出新异常。

本章小结
异常概念:所谓异常是指在程序运行的过程中发生的一些不正常事件(如:除0溢出,数组下标越界,所要读取的文件不存在)

异常导致的后果:Java程序的执行过程中如出现异常事件,可以生成一个异常类对象,该异常类对象封装了异常事件的信息,并将其被提交给java运行时系统,这个过程称为抛出异常,不处理的话就会导致程序直接中断

异常分类
Throwable:Error和Exception两大类
Error:系统运行java虚拟机的异常,这种异常解决不了
Exception:
Java异常处理机制
1、try…catch…finally
try:监控区域,执行可能产生异常的代码
catch:捕获、处理异常
finally:善后处理,无论是否发生异常,代码总能执行

try{}语句块中放的是要检测的java代码,可能会抛出异常,也可能会正常运行。
catch()(异常类型){ }块是当java运行时系统接收到try块中所抛出异常对象时,会寻找能处理这一异常catch块来进行处理(可以有多个catch块)
finally{ } 不管系统有没有抛出异常都会去执行里面的代码,一般来解放资源,除了在之前执行System.exit(0)

自定义异常
常见异常:RuntimeException,IOException,SQLException,ClassNotFoundException
自定义异常:Java提供的异常体系不可能预见所有希望加以报告的错误
自定义异常类必须从已有的异常类继承
建立新的异常类型最简单的方法就是让编译器产生默认构造方法
对异常来说,最重要的部分就是它的类名
可以为异常类定义一个接受字符串参数的构造方法,字符串参数描述异常信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值