Java异常机制
Java中为什么需要异常?
程序运行中出现异常就会终止程序。而我们可以通过捕获异常,使异常后面的程序正常运行。
Java中经常使用 try...catch
来捕获和处理异常
Java中的异常
- 采用面向对象的方式处理异常,过程如下
- 抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象交给JRE
- 捕获异常:JRE得到该异常后,寻找相应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止
- 下面的代码明显会出现异常,进行捕获并打印
public class test01 {
public static void main(String[] args){
try{
int a = 1/0;
System.out.println(a);
}
catch (Exception e ){
System.out.println(e);
}
}
}
- 控制台输出结果
java.lang.ArithmeticException: / by zero
Java异常的类图
- 继承自Throwable类
- Error:程序无法处理的错误,较为严重,一般是虚拟机运行时的错误,表示JVM处于不可恢复的崩溃状态,不需要管
- Exception:程序本身能够处理的异常
处理常见运行时异常
- NullPointerException异常:空对象导致的异常,要判断空指针
- ClassCastException异常:类型转换出现的异常,先判断类型
- ArrayIndexOutOfBoundsException异常:数组越界异常,先判断下标是否超过数组长度
- NumberFormatException异常:字符串中有非数字,无法转化为数字,要先判断
总的来说,运行时异常需要程序自己处理,需要添加逻辑判断来处理异常
处理已检查异常(编译期异常)
- 基本上交给虚拟机来处理,使用
try...catch
和throw
来做,即捕获异常或声明异常
下面一个例子,使用try...catch
来处理,即捕获异常:
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test02 {
public static void main(String[] args){
FileReader reader = null;
try {
reader = new FileReader("D:/2.txt");
char c1 = (char)reader.read();
System.out.println(c1);
} catch (FileNotFoundException e) {//子类异常在父类异常前面
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if(reader!=null){
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 注意可能出现异常时,子类异常要在父类异常前面,否则子类异常无法
catch
到
下面一个例子,使用throws
子句处理,即声明异常:
mport java.io.FileReader;
import java.io.IOException;
public class Test03 {
public static void main(String[] args) throws IOException {
//抛给main方法,main方法再抛给JRE
readMyFile();
}
//抛出一个大父类 IOException
public static void readMyFile() throws IOException {
FileReader reader = null;
reader = new FileReader("D:/2.txt");
char c1 = (char)reader.read();
System.out.println(c1);
if(reader!=null){
reader.close();
}
}
}
- 声明自身有可能抛出异常,谁调用谁就需要处理
- 层次型的框架一般可以将异常层层向上抛,到适合的层去处理
Java的自定义异常
可能会遇到JDK提供的任何标准异常类都无法满足要求的情况,这时可以创建自己的异常类,即自定义异常类。自定义异常类只需要从Exception类或它的子类派生一个子类即可。
- 自定义异常继承自
Exception
类,则为编译时异常,必须对其进行处理 - 不想处理,可以继承自运行时异常
RuntimeException
类
使用异常机制的建议
- 避免使用异常处理代替错误处理
- 处理异常不能代替简单测试
- 不要小粒度的处理异常,导致很多
try...catch
块 - 异常往往在高层处理