异常
- 异常信息由JVM打印
- 异常在java中以类的形式存在,每一个类都可以创建对象。JVM在执行到错误语句会new一个异常对象的构造方法的过程,然后由JVM将异常对象抛出。
- 异常类的结构
- 无论是错误或者异常都可抛出
- Error不可以处理,只要发生,就会终止JVM运行。
- Exception分为运行时异常和其他的Exception的直接子类(编译时异常):
- 运行时异常(RunTimeException)可以选择处理,也可以选择不处理,又被称为未受检异常或者非受控异常。
- 编译时异常不是在编译时发生的,表示必须在编写程序时预先处理,否则编译不通过,又被称为受检(受控)异常
- 运行时异常和编译时异常都是在运行的时候发生的。
区别:运行时异常发生概率小,编译时异常发生概率较高。正是因为如此,为了提高编写程序的高效性,规定编译时异常必须处理,运行时异常可以不预先处理。
异常处理方式
- 异常处理方式 :
- 上抛:在方法声明的位置上使用throws关键字,抛给上一次。
- 捕捉:使用try - catch语句块,进行异常捕捉。
- 当一个异常发生时,如果这个异常一直上抛给调用者,最终main方法会抛给JVM,则程序会终止。
- 如果一个方法抛出一个编译时异常,必须要预先处理:
- 使用throws继续上抛给调用者。
- 使用try-catch进行异常捕捉。
- 因为有的java类库中的方法本身就含有上抛给调用者的异常,若抛出的是一个编译时异常,则必须要预处理。
- 上抛时抛出的异常可以使程序有可能抛出的异常的父类异常,别的异常不可以。可以使用一个throws抛出多个不同的异常,用"," 隔开。
- 在main方法中的异常不建议上抛,使用try-catch进行捕捉。
try{
} catch(Exception e){
}// 引用e 保存的是底层代码所new出来的异常对象的内存地址。一抛一接。
- 若一个方法出现异常,
- try-catch语句后的语句可以执行,try语句块中该方法后的语句不可以执行。
- 若采用上抛形式,该方法后的所有语句都不会执行,相当于 return。
- try-catch
- catch的是本异常或者该异常的父类
- 若有多个catch分支,应遵循从子类异常到父类异常的顺序。
- 建议是一个准确的异常一个准确的异常精确处理,便于程序调试。
- throws 和 try-catch 的选择:
遵循一个原则:若需要调用者知道这一场的发生,则上抛,其余用捕捉。 - 异常对象的常用方法:
NullPointerException e = new NullPointerException("空指针异常");
String str = exception.getMessage(); //获取异常的简单描述信息 , 实际上获得的是有参构造方法的String参数
exception.printStackTrace();//打印异常追踪的堆栈信息
作用:在catch语句中显示异常信息
建议:在实际开发中使用printStackTrace()方法
- 堆栈异常信息的查看提醒:
- 从上往下看,跳过sun代码,看哪里出现了错误,找到根源,从而调试程序
- finally 字句
- 必须和try语句一起使用(有没有catch分支都行)
- 作用:通常在finally语句中进行资源关闭,比如IO流的关闭。
- 一些关于finally语句的小特殊情况:
try{
java语句1;
java语句2;
java语句3;
return;
}
finally{
java语句;
}
//注意到try语句中有return语句,但是finally中的java语句仍不受影响,仍会执行
try{
java语句1;
java语句2;
java语句3;
System.exit(0);//这种情况执行到此处直接退出JVM finally语句就不执行了。
}
finally{
java语句;
}
//注意到try语句中有return语句,但是finally中的java语句仍不受影响,仍会执行
- 代码的执行顺序:先try 后finally 最后return
- 实际原因是java的规则的冲突:
- 一是Java程序按照自上而下的顺序执行;
- 二是return语句执行后必须退出程序;
- 三是finally语句肯定会执行。
实例特殊情况:
public class ExceptionTest13 {
public static void main(String[] args) {
int result = m();
System.out.println(result); //100
}
/*
java语法规则:
java中有一条这样的规则:
方法体中的代码必须遵循自上而下顺序依次逐行执行
java中还有一条语法规则:
return语句一旦执行,整个方法必须结束
*/
public static int m(){
int i = 100;
try {
// 这行代码出现在int i = 100;的下面,所以最终结果必须是返回100
// return语句还必须保证是最后执行的。一旦执行,整个方法结束。
return i;
} finally {
i++;
}
}
}
/*
反编译之后的效果
public static int m(){
int i = 100;
int j = i;
i++;
return j;
}
*/
- 自定义异常 :Sun异常不够用,得看具体业务需要
使用方法:
- 定义一个类继承Exception(编译时异常)或者RuntimeException(运行时异常)
- 提供两个构造方法
- 一个有参
- 一个无参
public class MyException extends Exception{ // 编译时异常
public MyException(){
}
public MyException(String s){
super(s);
}
}
/*
public class MyException extends RuntimeException{ // 运行时异常
}
*/