文章目录
- 一、异常概述、体系
- 二、异常的分类
- 三、异常的默认处理流程
- 四、异常的处理机制
- 4.1 编译时异常的处理机制
- 4.1.1 方式一:抛出异常
- 4.1.2 方式二:捕获异常
- 4.1.3 方式三:前两者结合
- 4.2 运行时异常的处理机制
- 五、自定义异常
- 5.1 自定义编译时异常
- 5.2 自定义运行时异常
- 六、try-catch-finally格式
一、异常概述、体系
异常是程序在“编译”或者“执行”的过程中可能出现的问题。 如:数组索引越界、空指针异常、 日期格式化异常…
注意:语法错误不算在异常体系中。
异常体系如下:
Exception:java.lang 包下,称为异常类,它表示程序本身可以处理的问题。
RuntimeException 及其子类:运行时异常,编译阶段不报错,运行可能报错。 (空指针异常,数组索引越界异常)
除 RuntimeException 之外所有的异常:编译时异常,编译阶就报错,必须处理,否则代码不通过。 (日期格式化异常)。
Error:系统级别问题、JVM退出等,代码无法控制。
异常一旦出现了,如果没有提前处理,程序就会退出 JVM 虚拟机而终止。因此学习异常,通过提前处理异常,以达到避免异常的效果,体现的是程序的安全和健壮性。
二、异常的分类
异常分为:编译时异常和运行时异常。
简单来说,编译时异常就是在编译的时候出现的异常,运行时异常就是在运行时出现的异常。
运行时异常: 编译阶段不报错,运行时可能报错。一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误!常见运行时异常如下:
数组索引越界异常:ArrayIndexOutOfBoundsException
空指针异常:NullPointerException
数学操作异常:ArithmeticException
类型转换异常:ClassCastException
数字转换异常:NumberFormatException
编译时异常: 是担心程序员的技术不行,在编译阶段就爆出一个错误,目的在于提醒不要出错!
三、异常的默认处理流程
处理流程如下:
① 默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException。
② 异常会从方法中出现问题的点里抛出给调用者,调用者最终抛出给 JVM 虚拟机。
③ 虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。
④ 直接从当前执行的异常点干掉当前程序。
⑤ 后续代码没有机会执行了,因为程序已经死亡。
默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡。
四、异常的处理机制
4.1 编译时异常的处理机制
编译时异常是编译阶段就出错的,所以必须处理,否则代码根本无法通过。
编译时异常的处理方式有三种:
- 抛出异常:出现异常直接抛出去给调用者,调用者也继续抛出去。
- 捕获异常:出现异常自己捕获处理,不麻烦别人。
- 前两者结合:出现异常直接抛出去给调用者,调用者捕获处理。
4.1.1 方式一:抛出异常
格式:
规范格式:代表可以抛出一切异常。
public class ExceptionDemo01 {
public static void main(String[] args) throws Exception {
System.out.println("程序开始。。。。。");
parseTime("2011-11-11 11:11:11");
System.out.println("程序结束。。。。。");
}
public static void parseTime(String date) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
int i = 6/0; // 除零异常:ArithmeticException 异常
}
}
这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。
4.1.2 方式二:捕获异常
监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。
格式:
建议格式:
public class ExceptionDemo02 {
public static void main(String[] args) {
System.out.println("程序开始。。。。");
parseTime("2011-11-11 11:11:11");
System.out.println("程序结束。。。。");
}
public static void parseTime(String date) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
int i = 6/0; // 除零异常:ArithmeticException 异常
} catch (Exception e) {
e.printStackTrace(); // 打印异常栈信息
}
}
}
这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行。
4.1.3 方式三:前两者结合
方法直接将异通过 throws 抛出去给调用者,调用者收到异常后直接捕获处理。
public class ExceptionDemo03 {
public static void main(String[] args) {
System.out.println("程序开始。。。。");
try {
parseTime("2011-11-11 11:11:11");
System.out.println("功能操作成功~~~");
} catch (Exception e) {
e.printStackTrace();
System.out.println("功能操作失败~~~");
}
System.out.println("程序结束。。。。");
}
public static void parseTime(String date) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
int i = 6/0; // 除零异常:ArithmeticException 异常
}
}
实际应用中,只要代码能够编译通过,并且功能可以完成,那么每一种异常处理方式似乎也都是可以的。
4.2 运行时异常的处理机制
运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以。
按照规范建议还是处理:建议在最外层调用处集中捕获处理即可。
五、自定义异常
Java 无法为这个世界上全部的问题提供异常类,如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了。
优点:可以使用异常的机制管理业务问题,如提醒程序员注意。同时一旦出现 bug,可以用异常的形式清晰的指出出错的地方。
5.1 自定义编译时异常
编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理。
步骤:
① 定义一个异常类继承 Exception。
② 重写构造器。
③ 在出现异常的地方用 throw new 自定义对象抛出。
public class AgeIllegalException extends Exception{
public AgeIllegalException() {
}
public AgeIllegalException(String message) {
super(message);
}
}
public class ExceptionDemo {
public static void main(String[] args) {
try {
checkAge(300);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("程序结束了~~~~");
}
public static void checkAge(int age) throws AgeIllegalException {
if(age<0 || age>200){
// 抛出异常
// throw:在方法内部直接创建一个异常对象,并从此点抛出
// throws:用在方法申明上,抛出方法内部的异常
throw new AgeIllegalException(age + " is illegal");
}else{
System.out.println("年龄符合,继续执行");
}
}
}
5.2 自定义运行时异常
提醒不强烈,编译阶段不报错,运行时才可能出现!
步骤:
① 定义一个异常类继承 RuntimeException。
② 重写构造器。
③ 在出现异常的地方用 throw new 自定义对象抛出。
public class AgeIllegalRuntimeException extends RuntimeException{
public AgeIllegalRuntimeException() {
}
public AgeIllegalRuntimeException(String message) {
super(message);
}
}
public class ExceptionDemo {
public static void main(String[] args) {
try {
checkAge2(300);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("程序结束了~~~~");
}
public static void checkAge2(int age) {
if(age<0 || age>200){
// 抛出异常
throw new AgeIllegalRuntimeException(age + " is illegal");
}else{
System.out.println("年龄符合,继续执行");
}
}
}
六、try-catch-finally格式
finally:放在 try-catch 后面的,无论是正常执行还是异常执行代码,最后一定要执行,除非 JVM 退出。
作用:一般用于进行最后的资源释放操作(专业级做法)。
面试:
public class test {
public static void main(String[] args) {
System.out.println("算数结果:" + divided(10, 5));
}
public static int divided(int a, int b) {
int re = 0;
try {
re = a/b;
return re;
} catch (Exception e) {
System.out.println("除法出错");
return -1;
}finally {
System.out.println("最终方法执行");
}
}
}
控制台输出:
最终方法执行
算数结果:2
文章参考:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)