什么是异常?
- 异常是程序在“编译”或者“执行”的过程中可能出现的问题;
- 异常是应该尽量提前避免的;
- 异常可能也是无法绝对避免的,异常可能有太多情况
- 异常一旦出现,如果没有提前干预,程序就会退出JVM虚拟机
异常的体系
-
Java中异常继承的根类是:Throwable
-
Error:错误,严重错误的Error,无法通过处理的错误,一旦出现,程序员无能为力
-
Exception:异常类,它是开发中代码在编译或者执行的过程中可能出现的错误,它是需要提前处理的。
- 编译时异常:继承自Exception的异常或者子类,编译阶段就会报错
- 运行时异常:继承自RuntimeException的异常或者子类,编译阶段不会出错,它是在运行时可能出现的,运行时异常可以处理也可以不处理,编译阶段是不会出错的,但是在运行阶段可能出现,还是建议提前处理。
运行时异常的概念
- 继承自RuntimeException的异常或者其子类;
- 编译阶段是不会出错的,它是在运行时阶段可能出现的错误;
- 运行时异常编译阶段可以处理也可以不处理,代码编译都能通过
- 常见运行时异常列举:
- 1.数组索引越界异常: ArrayIndexOutOfBoundsException。
- 2.空指针异常 : NullPointerException。直接输出没有问题。但是调用空指针的变量的功能就会报错!!
- 3.类型转换异常:ClassCastException。
- 4.迭代器遍历没有此元素异常:NoSuchElementException。
- 5.数学操作异常:ArithmeticException。
- 6.数字转换异常: NumberFormatException。
编译时异常
- 在Java中,Exception类中除了RuntimeException类及其子类都是编译时异常。编译时异常的特点是Java编译器会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。
异常的默认处理机制
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("程序开始。。。。。。。。。。");
chu( 10 ,0 );
System.out.println("程序结束。。。。。。。。。。");
}
public static void chu(int a , int b){
System.out.println(a);
System.out.println(b);
int c = a / b ;// 出现了运行时异常,自动创建异常对象:ArithmeticException
System.out.println("结果是:"+c);
}
}
- 1.默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException;
- 2.异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机;
- 3.虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据;
- 4.直接从当前执行的异常点干掉当前程序;
- 5.后续代码没有执行机会,因为程序已经死亡。
编译时异常处理机制
方式一:直接异常抛出
- 在出现编译时异常的地方层层把异常抛出去给调用者,调用者最终抛出给JVM虚拟机。JVM虚拟机输出异常信息,直接干掉程序,这种方式与默认方式是一样的。虽然可以解决代码编译时的错误,但是一旦运行时真的出现异常,程序还是会立即死亡,这种方式并不好。
- 异常抛出的格式:
方法 throws 异常1 , 异常2 , ..{
}
建议抛出异常的方式:代表可以抛出一切异常,
方法 throws Exception{
}
public class ExceptionDemo01 {
public static void main(String[] args) throws Exception {
System.out.println("程序开始。。。。");
parseDate("2013-03-23 10:19:23");
System.out.println("程序结束。。。。。");
}
// Exception是异常最高类型可以抛出一切异常!
public static void parseDate(String time) throws Exception{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(time);
System.out.println(d);
InputStream is = new FileInputStream("D:/meinv.jpg");
}
}
方式二:在异常出现的地方捕获处理
- 在异常发生的地方,处理异常,并不会使程序直接死亡;
- 这种方法存在的问题是上层调用者不能直接的知道底层的执行情况;
- 语法:
try{
// 监视可能出现异常的代码!
}catch(异常类型1 变量){
// 处理异常
}catch(异常类型2 变量){
// 处理异常
}...
监视捕获处理异常企业级写法:
try{
// 可能出现异常的代码!
}catch (Exception e){
e.printStackTrace(); // 直接打印异常栈信息
}
//Exception可以捕获处理一切异常类型!
public class ExceptionDemo02 {
public static void main(String[] args) {
System.out.println("程序开始。。。。");
parseDate("2013-03-23 10:19:23");
System.out.println("程序结束。。。。。");
}
public static void parseDate(String time) {
try{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(time);
System.out.println(d);
InputStream is = new FileInputStream("D:/meinv.png");
} catch (Exception e) {
e.printStackTrace(); // 打印异常栈信息
}
}
// JDK 1.7之后
// public static void parseDate(String time) {
// try{
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Date d = sdf.parse(time);
// System.out.println(d);
//
// InputStream is = new FileInputStream("D:/meinv.png");
// } catch (FileNotFoundException|ParseException e) {
// e.printStackTrace(); // 打印异常栈信息
// }
// }
// public static void parseDate(String time) {
// try{
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss");
// Date d = sdf.parse(time);
// System.out.println(d);
//
// InputStream is = new FileInputStream("D:/meinv.png");
// } catch (FileNotFoundException e) {
// e.printStackTrace(); // 打印异常栈信息
// } catch (ParseException e) {
// e.printStackTrace(); // 打印异常栈信息
// }
// }
public static void parseDate1(String time) {
try{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss");
Date d = sdf.parse(time);
System.out.println(d);
InputStream is = new FileInputStream("D:/meinv.png");
} catch (FileNotFoundException e) {
System.err.println("文件根本不存在!");
} catch (ParseException e) {
System.err.println("解析有问题,请检查代码!");
}
}
}
方式三:在底层抛出异常,在上层统一捕获处理
- 底层出现的异常抛出给最外层调用者集中捕获处理。这种方案最外层调用者可以知道底层执行的情况,同时程序在出现异常后也不会立即死亡。
- 示例代码:
public class ExceptionDemo03 {
public static void main(String[] args) {
System.out.println("程序开始。。。。");
try {
parseDate("2013-03-23 10:19:23");
System.out.println("功能成功执行!!");
} catch (Exception e) {
e.printStackTrace();
System.out.println("功能执行失败!!");
}
System.out.println("程序结束。。。。。");
}
// 可以拦截所以异常!
public static void parseDate(String time) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(time);
System.out.println(d);
InputStream is = new FileInputStream("D:/meinv.png");
}
}
运行时异常处理机制
- 运行时异常在编译阶段是不会报错的,在运行阶段才会出错;
- 一旦程序出错,如果没有处理异常,那么程序还是会死亡;
- 运行时异常是自动往外抛出的,不需要我们手工抛出;
- 直接在最外层捕获处理即可,底层会自动抛出。
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("程序开始。。。。");
try{
chu(10 , 0);
System.out.println("操作成功!");
}catch (Exception e){
e.printStackTrace();
System.out.println("操作失败!");
}
System.out.println("程序结束。。。。");
}
public static void chu(int a , int b) {
System.out.println( a / b );
}
}
finally关键字
- 有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。例如,资源释放。
try{
// 可能出现异常的代码!
}catch(Exception e){
e.printStackTrace();
}finally{
// 无论代码是出现异常还是正常执行,最终一定要执行这里的代码!!
}try{
// 可能出现异常的代码!
}catch(Exception e){
e.printStackTrace();
}finally{
// 无论代码是出现异常还是正常执行,最终一定要执行这里的代码!!
}
在finally与return注意事项
- 情况一:finally代码块中的语句会先于return执行
public static int chu1(){
try{
int a = 10 / 2 ;
return a ;
}catch (Exception e){
e.printStackTrace();
return -1;
}finally {
System.out.println("=====finally被执行");
}
}
- 情况二:finally代码块中的return会覆盖其余位置的return
public static int chu1(){
try{
int a = 10 / 2 ;
return a ;
}catch (Exception e){
e.printStackTrace();
return -1;
}finally {
System.out.println("=====finally被执行");
return 111; // 不建议在finally中写return,会覆盖前面所有的return值!
}
}
网友评论