Throwable是Java所有异常的父类,也就是说Java所有的异常都继承自此类。 Throwable下面有两个子类,Error和Exception
Error指的是程序运行过程中的不应该出现的严重错误,Error不需要try{}catch(){}。常见的OutOfMemoryError内存不足的错误就是Error
Exception下面有RuntimeException和普通的Exception
RuntimeException是指程序运行中出现的不可恢复的错误,通常是代码编写的错误,也不需要try{}catch(){},常见的有IllegalArgumentException、IllegalStateException、NullPointerException、IndexOutOfBoundsException
最后我们谈到的是普通的Exception,普通的Exception是程序运行中出现的必须处理的异常,必须要对产生异常的代码进行try{}catch(){}或者在方法函数参数后面声明抛出异常throws SomeException
对象关系库中除了操作数据库的SQLExcpetion以外,最多的就是反射产生的异常(NoSuchMethodException、IllegalAccessException、InstantiationException、InvocationTargetException)。 对于异常,我们最关注的应该是
异常产生的原因是什么?异常是要处理还是要抛出?如果处理异常,怎么处理?我们的对象关系库是作为一个函数库使用,对外界只提供API调用,所以内部不能用日志记录异常信息(否则日志系统跟库互相侵入的太深),只能选择将所有异常抛出,在作为API被调用的地方抛出异常 首先我们的对象关系库是对数据库进行操作的,其中最广泛的异常就是SQLException异常,所以我们在使用这个库的时候应当保证异常的统一和明确,所以最好将所有的其他异常统一起来。 接下来我们讲讲如何主动抛出异常
public class SQLClass{ public void init()throws SQLException{ if(!clazz.isAnnotationPresent(Table.class)){ throw new SQLException(clazz+"类没有配置表名"); Table table=clazz.getAnnotation(Table.class); this.tableName=table.value(); //其他初始化 } }在SQLClass的初始化的过程中,如果一个类没有注解@Table来配置表名,这个程序肯定再也无法运行下去了,所以只能抛出异常,为了整个库的异常的体系的统一,应该抛出SQLException异常,并且为了更好更加详细的让程序员知道具体是在那儿发生了异常,异常产生的原因是什么,必须做好异常的说明。 除了主动抛出异常以外,其他程序产生的异常如何处理
public class SQLField{ //初始化属性的解析器 private ISQLFieldParser initParser() throws SQLException { Class<? extends ISQLFieldParser> parserClass = column.parser(); try { Constructor<? extends ISQLFieldParser> constructor = parserClass.getDeclaredConstructor(); constructor.setAccessible(true); return constructor.newInstance(); } catch (Exception e) { throw new SQLException(field + "的解析器初始化失败,解析器为:" + parserClass,e); } } }在上面的解析器的初始化过程中会产生很多的反射相关的异常。 如果我们选择将所有异常直接抛出的话,估计方法上要么带了很长很长的异常声明,要么方法上直接抛出Exception,导致调用者无法得知具体的异常问题。 所以问题的关键在于我们如何处理这些异常 我们选择将这些异常进行捕获,然后抛出统一SQLException异常,接着对异常进行详细的说明,并且在新的异常里面把原来的异常也包裹进来,形成异常链。
异常链就是在抛出新的异常的同时将原来的异常包裹进来,这样形成了一层一层的异常,方便出现异常时对异常产生的位置进行追踪。
通过上面的两种方法,我们能够保证对象关系库有着统一的异常,并且在异常产生的时候能够方便的查找到异常产生的地方。
