Java异常
异常就是在程序的运行过程中所发生的意外事件,它中断指令的正常执行。可能导致程序发生非正常情况的原因有很多,如数组下标越界、算术运算被0除、空指针访问、试图访问不存在的文件等。
异常的类层次(常见)
Java 异常处理机制:
Error: 错误 Error 类指的是系统错误或运行环境出现的错误,这些错误一般是很严重的错误,即使捕捉 到也无法处理,由 Java 虚拟机生成并抛出,包括系统崩溃、动态 链接失败、虚拟机错误等,在 Java 程序中 不做处理。
Exception: 异常 Exception 类则是指一些可以被捕获且可能恢复的异常情况,是一 般程序中可预知的问 题。对于异常可分为两类:
- (1) 运行时异常:由系统检测, 用户的 Java 程序中可以不做处理,系统将它们交给 缺省的异常处理程序,例如:
public class TestDemo{
public static void main(String[] args) {
int[] arr = new int[10];
arr[10] = 100;
System.out.println(arr[10]);
}
}
编译期间不报错,运行期间异常(下标越界)
- (2) 非运行时异常:在程序中必须对其进行处理,否则编译器会指出错误。
编译时报错,需要进行异常处理
异常的处理结构
- Java 异常处理通过 5 个关键字 try,catch,finally,throw 和 throws 进行管理
- Java 中处理异常有两种方式:捕获异常、声明抛出异常。
捕获异常:就地解决,并使程序继续执行。
声明抛出异常:就是将异常向外转移,即将异常抛出方法之外,由调用该方法的环境去处理。
捕获异常
try: 捕获异常的第一步是用 try{…}选定捕获异常的范围,try 模块中的语句是程序正常流程要执行的语句,但 是在执行过程中有可能出现异常。所有可能抛出异常的语句都放入 try 模块中。
catch(必有): 每个 try 代码块可以伴随一个或多个 catch 语句,用于处理 try 代码块中所生成的异常事件。catch 语句只 需要一个形式参数指明它所能够捕获的异常类型,这个类必须是 Throwable 的子类,运行时系统通过参数值把被 抛弃的异常对象传递给 catch 块。在 catch 块中是对异常对象进行处理的代码,与访问其它对象一样,可以访问一个异常对象的数据成员或调用它的方法。
- getMessage()是类 Throwable 所提供的方法,用来得到有关异常事件的信息,
- 类 Throwable 还提供了方法 printStackTrace()用来跟踪异常事件发生时执行堆栈的内容。
catch 语句的顺序: 捕获异常的顺序和 catch 语句的顺序有关,当捕获到一个异常时,剩下的 catch 语句就 不再进行匹配。因此, 在安排 catch 语句的顺序时,首先应该捕获最特殊的异常,然后 再逐渐一般化。也就是一般先安排子类,再安排父类。
finally(可选) : 捕获异常的最后一步是通过 finally 语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分 以前,能够对程序的状态作统一的管理。不论在 try 代码块中是否发生了异常事件,finally 块中的语句都会被执行。
try{
语句块;
}
catch(异常类名 参变量名) { 语句块; }
finally { 语句块; }
抛出异常
在 Java 程序的执行过程中,如果出现了异常事件,就会生成一个异常对象。生成的异常对象将传递给 Java 运 行时系统,这一异常的产生和提交过程称为抛出(throw)异常。
声明抛出异常
(1) 一个方法不处理它产生的异常,而是沿着调用层次向上传递,由调用它的方法来处理这些异常,叫声明抛出异常(throws)。声明抛出异常是一种消极的异常处理机制。
(2) 抛出异常就是产生异常对象的过程,首先要生成异常对象,异常或者由虚拟机生成,或者由某些类的实例 生成,也可以在程序中生成。在方法中,抛出异常对象是通过 throw 语句实现的。
注意:
IOException e = new IOException();
throw e;
- 可以抛出的异常必须是 Throwable 或其子类的实例。
- throws 子句中同时可以指明多个异常,之间由逗号隔开。
- 对 Error 类或其子类的对象,程序中不必进行处理。
- 对 RuntimeException 类或其子类,程序中可以不必进行处理。
- 除此之外的异常,程序员都应该在程序中进行处理。
处理方式分为以下几种:
① 要么用 try-catch-finally 进行捕获处理
② 要么明确表示不处理从而声明抛出异常
③ 要么先捕获处理然后再次抛出。
在进行异常处理过程中应该注意:
Java 的异常处理机制(try-catch-finally 语句、throws 子句、throw 语句)会带来 Java 程序代码结构上的改变。
① 不能滥用异常机制。简单的出错判断建议用 if 语句。
② 不要过分细分异常。
自定义异常
1、自定义异常类设计
在程序中,可以创建自定义的异常类。用户定义的异常必须继承自 Throwable 或 Exception 类,建议用 Exception 类。
2、抛出异常
例如:
//自定义异常类
class MyException extends Exception{
String id;//异常标识
public MyException(String str){
id=str;
}
public String toString(){
return ("异常:"+id);
}
}
public class TestDemo {
public static void main(String[] args) {
try{
throw new MyException("一个测试异常!");
}catch(MyException e){
System.out.println(e);
}
}
}
结果:
3、方法的异常声明
修饰符 返回类型 方法名(参数列表) throws 异常类名列表{
...
throw 异常类名;
...
}
总结
异常处理(一般只针对编译期异常) -> 五个关键字(try catch finally throw throws)
一个try块对应一个或者多个catch块
1、try:
注意:
- 1)如果当前try块中存在多条可能会发生异常的代码A,B C 三条语句,如果A发生异常,此时B,C语句不会被执行到。
- 2)try块尽量避免嵌套
public class TestDemo{
public static void main(String[] args) {
//只关心ClassNotFoundException
int[] arr = {0};
//可能发生异常的代码
try {
arr[1] = 10;//JVM抛出异常对象
Thread.sleep(1000);
//return之前调用finally
// return;
System.exit(0);
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}catch (InterruptedException e){
e.printStackTrace();
}finally {//特点是:无论是否发生异常必定会被执行到
System.out.println("finally");
System.exit(0);
// return;
}
}
}
2、catch -> 尽量避免过细划分异常
注意:
catch(NullPointerException){ //先用关心的子类处理,不关心的直接用父类处理
}catch(Exception e){
}
3. finally: 特点是:无论是否发生异常必定会被执行到
TODO: 1) final finally finalize
TODO:2)如果try块里面包含 return;并且finally块也包含return;
从finally块return退出
TODO: 3) 如果try块里面含有退出System.exit();finally也包含:问:此时从哪里退出
从try块中System.exit退出
4、throw:
扔异常对象
例如:throw new EmptyStackException();
class MyStack{
private int[] element;
private int size;
public static final int CAPACITY = 10;
public MyStack(){
this(CAPACITY);
}
public MyStack(int num){
element = new int[num];
}
public int peek(){
if(size == 0){//EmptyStackException
throw new EmptyStackException();
}
return element[size-1];
}
}
5、throws
void fun()throws InterruptedException{
Thread.sleep(1000);//(单位毫秒)
}
//调用处:
try{
fun();//谁调谁处理
}catch(InterruptedException e){
e.printStackTrace();
}