Java异常处理

一、异常的分类

JDK中定义了很多异常类,这些类对应了各种各样可能出现的异常事件。

Error:称为错误,由Java虚拟机(JVM)生成并抛出,包括动态链接失败、虚拟机错误等。程序对其不作处理。

Exception:所有异常类的父类,其子类对应了各种各样可能出现的异常事件。一般需要用户显式的声明或捕获。

RuntimeException:运行时异常,如被0除、空指针、数组下标越界等,系统会自动检测并将它们交给缺省的异常处理程序。用户可不必对其进行处理,但用户可在之前对其进行判断以避免RuntimeException。

注意:RuntimeException可以不捕捉,其他Exception必须捕捉和处理。

二、使用自定义异常

步骤如下:

1.通过继承java.lang.Exception类声明自己的异常类

2.在方法适当的位置,生成自定义异常的实例,并throw

3.在方法的声明部分用throws声明该方法可能抛出的异常

示例:

class MyException extends Exception {	//继承Exception类
	private int id;
	public myException(String message, int id) {
		super(message);
		this.id = id;
	}
	public int getId() {
		return id;
	}
}
public class TestRegist {
	public void regist(int num) throws MyException {	//throws:可能抛出MyException异常
		if (num < 0) {
			throw new MyException("人数为负值,不合理", 3);	//throw:遇到情况,抛出异常
		}
		System.out.println("登记人数" + num);
	}
	public void manager() {
		try {
			regist(100);
		} catch (MyException e) {
			System.out.println("登记失败,出错类型码=" + e.getId());
			e.printStackTrace();
		}
		System.out.print("操作结束");
	}
	public static void main(String[] args) {
		TestRegist t = new TestRegist();
		t.manager();
	}
}

三、异常与重写的关系

注意:重写方法需要抛出与原方法所抛出异常类型一致异常或不抛出异常。

四、异常处理的一些常见误区

1.catch到Exception后,只是单纯的printStackTrace。

这实际上未对异常进行任何处理,属于“丢弃异常”。printStackTrace对我们调试程序有帮助,但程序调试阶段结束之后,printStackTrace就不应再在异常处理模块中担负主要责任了。

正确的做法:

(1)处理异常

针对该异常采取一些行动,例如修正问题、提醒某个人或进行其他一些处理,要根据具体的情形确定应该采取的动作。再次说明,调用printStackTrace算不上已经“处理好了异常”。

(2)重新抛出异常

处理异常的代码在分析异常之后,认为自己不能处理它,重新抛出异常也不失为一种选择。

(3)把该异常转换成另一种异常

大多数情况下,这是指把一个低级的异常转换成应用级的异常(其含义更容易被用户了解的异常)。

(4)干脆不捕获异常

结论一:既然捕获了异常,就要对它进行适当的处理。不要捕获异常之后又把它丢弃,不予理睬。

2.catch(Exception e),用一个catch捕获所有的异常。

catch语句表示我们预期会出现某种异常,而且希望能够处理该异常。

异常类的作用就是告诉Java编译器我们想要处理的是哪一种异常。

结论二:在catch语句中尽可能指定具体的异常类型,必要时使用多个catch。不要试图处理所有可能出现的异常。

3.占用资源未释放

异常会改变程序正常的执行流程。如果程序用到了文件、Socket、JDBC连接之类的资源,即使遇到了异常,也要正确释放占用的资源。

结论三:保证所有资源都被正确释放,充分运用finally关键词。

4.catch到Exception后,只是简单的打印堆栈,而不说明异常的详细信息

catch到Exception后,我们只知道当前正在处理的类发生了某种错误,但却不能获得任何信息判断导致当前错误的原因。

printStackTrace的堆栈跟踪功能显示出程序运行到当前类的执行流程,但只提供了一些最基本的信息,未能说明实际导致错误的原因,同时也不易解读。

因此,在出现异常时,最好能够提供一些文字信息,例如当前正在执行的类、方法和其他状态信息,包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。

结论四:在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读。

5.一个try块包揽全局

把大量的代码放入单个try块,然后再在catch语句中声明Exception,而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难,因为一大段代码中有太多的地方可能抛出Exception。

结论五:尽量减小try块的体积。

6.隐形杀手:数据不完整

不完整的数据是程序的隐形杀手。如果输出数据的过程中抛出了异常,输出过程被打断,然后运行catch块……就这些,再也没有其他动作了。

已经输出的数据怎么办?使用这些数据的人或设备将收到一份不完整的(因而也是错误的)数据,却得不到任何有关这份数据是否完整的提示。对于有些系统来说,数据不完整可能比系统停止运行带来更大的损失。

较为理想的处置办法是向输出设备写一些信息,声明数据的不完整性;另一种可能有效的办法是,先缓冲要输出的数据,准备好全部数据之后再一次性输出。

结论六:全面考虑可能出现的异常以及这些异常对执行流程的影响。

范例:

OutputStreamWriter out = //... 
java.sql.Connection conn = //... 
try {
	Statement stat = conn.createStatement();
	ResultSet rs = stat.executeQuery("select uid, name from user");
	while (rs.next()) {
		out.println("ID:" + rs.getString("uid") + ",姓名: " + rs.getString("name"));
	}
} catch(SQLException sqlex) {
	out.println("警告:数据不完整");
	throw new ApplicationException("读取数据时出现SQL错误", sqlex);
} catch(IOException ioex) {
	throw new ApplicationException("写入数据时出现IO错误", ioex);
} finally {
	if (conn != null) {
		try {
			conn.close();
		} catch(SQLException sqlex2){
			System.err(this.getClass().getName() + ".mymethod - 不能关闭数据库连接: " + sqlex2.toString());
		}
	}
	if (out != null) {
		try {
			out.close();
		}catch(IOException ioex2){ 
			System.err(this.getClass().getName() + ".mymethod - 不能关闭输出文件" + ioex2.toString());
		}
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值