当某段java代码中出现错误或异常时,会在引起错误代码的方法中自动创建异常对象,如果不进行处理系统会调subruntime()中断程序的继续运行。
我们通常使用try{}catch{}finally{}捕获处理代码块运行错误产生的异常对象,我们也可以自定义异常类对特定的异常进行处理,或者不在该方法中处理异常而是在该方法名后面throws加特定异常类,将特定异常对象向外继续传递异常,不过不管使用哪种方法代码错误产生的异常对象最终都会被捕获处理。
当然也可以在代码块中用throw 加new 某个异常类手动生成一个异常类实例对象,通常用于向方法的调用者报告某些错误条件。
1.异常处理的java关键字
java异常处理通常使用五个关键字进行管理:try,catch,finally,throw,throws进行处理。
try代码块封装可能发生异常的代码块,try代码块中某句代码报错产生异常对象程序运行将跳出该try代码块,异常对象逐一匹配不同分支catch代码块进行处理异常,异常处理完毕继续执行try{}catch{}后面的代码程序继续运行,如果没有相匹配的catch代码块进行捕获处理,则要么通过方法名傍边throws创建的特定异常管道将产生往外抛然后继续运行程序,要么java系统处理报错并调用subruntime()中断程序的运行。try{}不能单独使用,需要配合finally{}或者catch{}成套使用,不管try{}代码块是否产生异常,finally{}都会在后面被执行,就算在try{代码块中}调用return关键字中断方法,finally{}中的代码块也会在方法调用完成前被执行。
1.1try的嵌套使用
代码示例1:
public class finallyDeme {
public static void main(String[] args) {
try {
int a = args.length;
int b = 24 / a;
if (a == 1) {
int c = 24 / (a - 1);
}
if (a == 2) {
int d[] = {};
d[34] = 12;
}
// 嵌套的try语句
try {
Object object = null;
String e = object.toString();
} catch (NullPointerException e) {
System.out.println("空指针异常");
// TODO: handle exception
}
} catch (ArithmeticException e) {
System.out.println("除数为零算术异常");
// TODO: handle exception
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界异常");
// TODO: handle exception
} finally {
System.out.println("finally代码块一般用来释放代码报异常前使用的资源");
}
System.out.println("处理完异常继续执行trycatch外的程序代码。");
}
}
执行结果:
数组下标越界异常
finally代码块一般用来释放代码报异常前使用的资源
处理完异常继续执行trycatch外的程序代码。
1.2return并不能阻止finally代码的执行
代码示例2:
public class finallyDemo {
//如果方法内会产生某些异常则需要通过throws指明方法会抛出的异常种类,以便调用者了解
static void procssA() throws NullPointerException{
try {
throw new NullPointerException("自定义的空指针异常A");
} catch (NullPointerException e) {
//捕获以后再抛出去
throw e;
}
}
static void procssB(){
try {
System.out.println("在方法B内部");
throw new RuntimeException("自定义的运行异常B");
} finally {
System.out.println("B的finally");
}
}
static void procssC(){
try {
System.out.println("在方法C内部");
return;
} finally {
System.out.println("C的finally");
}
}
public static void main(String[] args) {
try {
procssA();
} catch (Exception e) {
System.out.println(e+"被捕获");
}
try {
procssB();
} catch (Exception e) {
System.out.println(e+"被捕获");
}
procssC();
}
}
执行结果:
java.lang.NullPointerException: 自定义的空指针异常A被捕获
在方法B内部
B的finally
java.lang.RuntimeException: 自定义的运行异常B被捕获
在方法C内部
C的finally
2.异常继承结构
Throwable(顶级类)
|- Error 系统级错误类比如堆栈溢出,只能重启程序
|- Exception 可修复的错误类,必须处理
Exception:
|- 其他Exception(可检查异常(编译期异常))
|- RuntimeException(有默认抛出管道,可以不用throws或try-catch,java系统会捕获异常并打印在控制台上)(运行时异常,非检查异常)
|- NullPointerException
|- ArrayIndexOutOfBoundsException
|- NumberFormatException
|- ArithmeticException
|- ClassCastException
|- …
3.java的内置异常(有默认抛出管道可以不自行处理java.lang.)
异常 | 含义 |
---|---|
ArithmeticException | 算术运算错误比如除零 |
ArrayIndexOutOfBoundsException | 数组下标越界 |
ArrayStoreException | 使用不兼容的类型为数组元素赋值 |
ClassCastException | 类型转换异常,比如将字符串“a”强制转换成Interger |
EnumConstantNotPresentException | 尝试使用未定义的枚举值 |
IllegalAccessException | 非法访问权限异常,比如访问其他类的私有变量 |
IllegalMonitorStateException | 非法的监视器操作,比如当前线程没有使用 synchronized获得某对象的锁,却调用该对象的notify(),wait()等方法 |
IllegalArgumentException | 非法参数异常,比如调用某方法却给了一个不合格类型的传参 |
IllegalStateException | 程序处于非法状态异常,比如当前对客户端的响应已经结束,却在响应已经结束(或说消亡)后再向客户端(实际上是缓冲区)输出内容 |
IllegalThreadStateException | 线程状态非法异常,比如同一个线程多次调用start()进行启动 |
IndexOutOfBoundsException | 下标越界异常 |
NegativeArraySizeException | 自然数数组异常,比如用负数给自然数数组元素赋值 |
NullPointerException | 空指针异常,调用为空的对象中的属性,因为空引用,引用不指向任何一块堆内存地址 |
NumberFormatException | 数字格式化异常,比如将123/230转换成一个整数 |
SecurityException | 安全性异常,比如由于版本不同jar包不兼容问题 |
StringIndexOutOfBoundsException | 字符串下标越界异常 |
TypeNotPresentException | 类型未定义异常,当访问未定义的类型变量时,以及当加载类型(例如,类、接口或注释类型)时出现,此异常和ClassNotFoundException 不同,ClassNotFoundException 是一个经过检查的异常,而此异常是未经检查的 |
UnsupportedOperationException | 不支持操作异常,比如java数组转换成list集合后,调用其add()或remove()时出现,因为Arrays.asList() 返回java.util.Arrays A r r a y L i s t 而 不 是 A r r a y L i s t 。 A r r a y s ArrayList而不是ArrayList。Arrays ArrayList而不是ArrayList。ArraysArrayList和ArrayList都是继承AbstractList,remove,add等 method在AbstractList中是默认throw UnsupportedOperationException而且不作任何操作。 |
ClassNotFoundException | 类没找到或未定义异常 |
CloneNotSupportedException | 不支持克隆异常,没有实现Cloneable接口却通过对象调用clone() |
InstantiationException | 实例化异常,比如为抽象类或接口创建对象 |
InterruptedException | 中断异常,比如向一个处于堵塞状态的线程发送中断请求interrupt()时出现 |
NoSuchFieldException | java反射异常,导致的原因通常为没有对应字段或属性为私有时获取Field用的方法不是getDeclaredField。 |
NoSuchMethodException | 方法无法访问异常,比如访问一个私有化的方法 |
ReflectiveOperationException | 由反射操作引起的异常的公共超类 |
4.自定义异常以及链式异常
创建一个异常类,也就是创建Exception或者Throwable的子类
链式异常也就是为一个异常关联另一个异常,将第二个异常描述为第一个异常的导致原因,Exception和Throwable都有用于链式异常或自定义异常的构造函数。
Throwable()
Throwable(String message)
Throwable(String message, Throwable cause)
Throwable(Throwable cause)
示例代码:
public class ChainExcDemo {
// 这两种异常都是java内置的RuntimeException可以不使用throws铺设抛管道和捕获
static void demoProcess() throws NullPointerException {
// 也可以直接new异常不用throw关键字
//NullPointerException e = new NullPointerException("顶级异常");
try {
throw new NullPointerException("顶级异常");
} catch (Exception e) {
// 通过initCause()定义导致异常
e.initCause(new ArithmeticException("起因异常"));
throw e;
}
}
public static void main(String[] args) {
try {
demoProcess();
} catch (Exception e) {
System.out.println(e);
System.out.println(e.getCause());
}
}
}
运行结果:
java.lang.NullPointerException: 顶级异常
java.lang.ArithmeticException: 起因异常