我们平时程序中都遇到过异常处理的问题,今天抽时间总结下java的异常处理机制。
首先我们来看异常的分类:
Error 系统级别的错误: Java 运行时环境出现的错误,不可控。Exception 是程序级别的错误:编译阶段的错误,可控。
异常结构中的父类 Throwable 类,其下子类 Exception类和 Error 类。我们在程序中可以捕获的是 Exception 的子类异常。
1、异常处理语句: try-catch,如果 try 块捕获到异常,则到 catch 块中处理,否则跳过忽略 catch 块(开发中,一定有解决的办法才写,无法解决就向上抛 throws)。try{//关键字,只能有一个 try 语句
可能发生异常的代码片段
}catch(Exception e){//列举代码中可能出现的异常类型,可有多个 catch 语句
当出现了列举的异常类型后,在这里处理,并有针对性的处理
}
2、良好的编程习惯,在异常捕获机制的最后书写 catch(Exception e)捕获未知的错误(或不需要针对处理的错误)。
3、catch 的捕获是由上至下的,所以不要把父类异常写在子类异常的上面,否则子类异常永远没有机会处理,在 catch 块中可以使用方法获取异常信息:
(1)getMessage()方法:用来得到有关异常事件的信息。
(2)printStackTrace()方法:用来跟踪异常事件发生时执行堆栈的内容。
4、throw 关键字:用于主动抛出一个异常当我们的方法出现错误时,这个错误我们不应该去解决,而是通知调用方法去解决时,会将这个错误告知外界,而告知外界的方式就是 throw 异常(抛出异常) catch 语句中也可抛出异常。 虽然不解决,但要捕获,然后抛出去。
使用环境:
我们常在方法中主动抛出异常,但不是什么情况下我们都应该抛出异常。原则上,自身决定不了的应该抛出。那么方法中什么时候该自己处理异常什么时候抛出?方法通常有参数,调用者在调用我们的方法帮助解决问题时,通常会传入参数,若我们方法的逻辑是因为参数的错误而引发的异常,应该抛出。
5、throws 关键字:不希望直接在某个方法中处理异常,而是希望调用者统一处理该异常。声明方法的时候,可以同时声明可能抛出的异常种类,通知调用者强制捕获。原则上 throws 声明的异常,一定要在该方法中抛出。否则没有意义。相反的,若方法中主动通过 throw 抛出一个异常,应该在 throws 中声明该种类异常,通知外界捕获。
(1)注意 throw 和 throws 关键字的区别:抛出异常和声明抛出异常。
(2)不能在 main 方法上 throws,因为调用者 JVM 会直接关闭程序。
6、捕获异常两种方式:
(1)添加 try-catch捕获该异常,
(2)在方法中声明出也追加这种异常的抛出(继续往外抛)。
7、 java 中抛出异常过程: java 虚拟机在运行程序时,一旦在某行代码运行时出现了错误,JVM 会创建这个错误的实例,并抛出。这时 JVM 会检查出错代码所在的方法是否有 try 捕获,若有,则检查 catch 块是否有可以处理该异常的能力(看能否把异常实例作为参数传进去,看有没有匹配的异常类型)。若没有,则将该异常抛给该方法的调用者(向上抛)。以此类推,直到抛至 main 方法外仍没有解决(即抛给了 JVM 处理)。那么 JVM 会终止该程序。8、java 中的异常 Exception 分为:
(1)非检测异常( RuntimeException 子类):编译时不检查异常。若方法中抛出该类异常或其子类,那么声明方法时可以不在 throws 中列举该类抛出的异常。常见的运行时异常有:
NullPointerException
IllegalArgumentException
BufferOverflowException
ClassCastException
ConcurrentModificationException
NumberFormatException
ArrayIndexOutOfBoundsException
ArithmeticException
(2)可检测异常(非 RuntimeException 子类):编译时检查,除了运行时异常之外的异常,都是可检查异常,则必须在声明方法时用 throws 声明出可能抛出的异常种类9、finally 块: finally 块定义在 catch 块的最后(所有 catch 最后),且只能出现一次( 0- 1 次), 无论程序是否出错都会执行无条件执行!通常在 finally 语句中进行资源的消除工作,如关闭打开的文件,删除临时文件等。
例:事务提交中的异常处理
try {
//设置事务的提交方式为非自动提交:
connection.setAutoCommit(false);
//创建执行语句
String sql = "insert into dec_project_change (pro_name,manager,company) values (#{pro_name},#{manager},#{company}},'项目终止')";
//分别执行事务
ps = connection.prepareStatement(sql);
ps.executeUpdate();
//在try块内添加事务的提交操作,表示操作无异常,提交事务。
connection.commit();
connection.setAutoCommit(true);
} catch (Exception ex) {
try{
connection.rollback();
}catch(Exception e){
e.printStackTrace();
}
ex.printStackTrace();
}finally{
try{
ps.close();
connection.close();
}catch(Exception e){
e.printStackTrace();
}
}
10、重写方法时的异常处理
如果使用继承时,在父类的某个地方 throws了某些异常,而在子类别中重新定义该方法时,可以:
(1)不处理异常(重新定义时不设定 throws)。
(2)可仅 throws 父类别中被重新定义的方法上的某些异常(抛出一个或几个)。
(3)可 throws 被重新定义的方法上的异常的子类别(抛出异常的子类)。
不可以:
(1)throws 出额外的异常。
(2)throws 被重新定义的方法上的异常的父类别(抛出了异常的父类)。