java中,将程序运行中的发生的不正常情况称为异常。可将其分为错误和异常,错误是指java虚拟机无法解决的问题,常见有栈溢出(StackOver)和内存耗尽(OutOfMemory),异常又可以划分为两类,编译时异常(受检异常)和运行时异常(非受检异常)。如下图(简约版异常体系图)
运行时异常是指RuntimeException及其子类,一般是由于代码设计的逻辑错误导致,不强制要求处理,但因为发生异常会默认采用将异常抛出的方式而导致程序崩溃,所以建议避免出现此类异常。
常见的运行时异常有
// 常见的运行时异常
// NullPointerException
// String str = null;
// str.equals("");
// Exception in thread "main" java.lang.NullPointerException
// ArithmeticException 算术异常
// eg
// int nm = 1 / 0;
// Exception in thread "main" java.lang.ArithmeticException: / by zero
// ClassCastException 类型转换异常
// eg.
// Object obj = new String();
// Integer ite = (Integer)obj;
// Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
// ArrayIndexOutOfBoundsException 索引越界异常
// Integer [] arr = new Integer[3];
// int i = arr[3];
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
// NumberFormatException 数字格式异常
// eg
// Integer.parseInt("123你");
// Exception in thread "main" java.lang.NumberFormatException: For input string: "123你"
编译时异常故名思意,发生在编译阶段,如果不处理则无法通过编译
常见的编译时异常
SqlException
IoException
ClassNotFoundException
异常处理
1.throws 将异常抛出,交给方法的调用者解决(甩锅型)
2.try...catch...finally
throws的处理流程(一般用于不确定如何处理异常,将异常抛出,由调用者去处理)
eg.
public static void main(String[] args) throws FileNotFoundException {
InputStream is = new FileInputStream(new File("E:"));
}
try...catch...finally使用
try{
...// 可能出现异常的代码
}
catch(xxxException e){
...//异常处理的逻辑
// 这里可以使用多个catch捕获不同的异常,如果多个catch捕获的异常中存在继承关系,必须先捕获子类异
// 常
}
finally{
...// 一定会执行,多用于资源释放
}
// 另外,三者可以进行多种组合,如try...finally/ try... catch
关于 try...catch...finally的练习
public static void main(String[] args) {
try{
System.out.println("异常发生前");
int a = 1/0;
System.out.println("异常发生后");
}
catch(ArithmeticException e){
System.out.println("异常处理");
}
finally {
System.out.println("关闭资源");
}
}
运行结果为
不难看出,异常发生后,直接执行catch块中的语句,跳过try块中剩余的语句,最后执行finall块中的语句,这就是一个try...catch...finally的执行流程
public static int testException(){
int i;
try {
i = 1;
i = i / 0;
return i;
}
catch (ArithmeticException e){
return i=3;
}
finally {
return i = 4;
}
}
执行结果为
上述代码在发生异常进入catch块,执行 return语句 i = 3; 会将结果先寄存在栈中,并不会直接返回,然后执行finally语句,因为finally中也有return语句,就更新寄存的值并返回。
将上面的代码稍微改动一下
public static int testException(){
int i;
try {
i = 1;
i = i / 0;
return i;
}
catch (ArithmeticException e){
return i=3;
}
finally {
i = 4;
}
}
执行结果
同样,发生异常进入catch块中执行return语句,这里将 3寄存在栈中,然后执行finally将 i的值改为3,但返回的值是栈中寄存的值。
再次改变上面的代码。每天上一当,当当不一样
public static int[] testException(){
try {
arr[0] = 1;
arr[0] = arr[0] / 0;
return arr;
}
catch (ArithmeticException e){
arr[0] = 3;
return arr;
}
finally {
arr[0]= 4;
}
}
运行结果
arr[0] = 4;
和之前一样,发生异常执行catch中语句后执行return,将arr的地址寄存在栈中,finally执行后,返回之前catch块寄存在栈中的地址,在这之前对该地址指向空间的元素进行的修改都是有效的。
自定义异常类
作用:程序中出现的异常在Throwable的子类中没有描述处理,就可以通过diy的方式去设计异常类
方法:继承Exception或RuntimeException
提供构造方法