目录
c. 前两者结合,出现异常直接抛出去给调用者,调用者捕获处理。
一、异常概述、体系
1、什么是异常?
异常是程序在“编译”或者“执行”的过程中可能出现的问题。
注意:语法错误不算在异常体系中。
比如:数组索引越界、空指针异常、 日期格式化异常,等…
2、为什么要学习异常?
异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止。
研究异常并且避免异常,然后提前处理异常,体现的是程序的安全, 健壮性。
3、异常体系
4、Error
Exception:java.lang包下,称为异常类,它表示程序本身可以处理的问题。
RuntimeException及其子类:运行时异常,编译阶段不会报错。 (空指针异常,数组索引越界异常)
除RuntimeException之外所有的异常:编译时异常,编译期必须处理的,否则程序不能通过编译。 (日期格式化异常)
5、编译时异常和运行时异常
编译时异常:是在编译成class文件时必须要处理的异常,也称之为受检异常。(编译时异常就是在编译的时候出现的异常)
运行时异常:在编译成class文件不需要处理,在运行字节码文件时可能出现的异常。(运行时异常就是在运行时出现的异常)
二、常见运行时异常
1、运行时异常
直接继承自RuntimeException或者其子类:编译阶段不会报错,运行时可能出现的错误。
2、运行时异常示例
数组索引越界异常: ArrayIndexOutOfBoundsException
空指针异常 : NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
数学操作异常:ArithmeticException
类型转换异常:ClassCastException
数字转换异常: NumberFormatException
运行时异常:一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误, 自己的水平有问题!
三、常见编译时异常
1、编译时异常
不是RuntimeException或者其子类的异常:编译阶就报错,必须处理,否则代码不通过。
2、编译时异常示例
String date = "2015-01-12 10:23:21";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date); //日期解析异常:ParseException
System.out.println(d);
3、编译时异常的作用是什么?
是担心程序员的技术不行,在编译阶段就爆出一个错误, 目的在于提醒不要出错!
编译时异常是可遇不可求。遇到了就遇到了呗。
四、异常的默认处理流程
1、默认异常处理机制。
默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡!
五、编译时异常的处理机制
1、概念
编译时异常是编译阶段就出错的,所以必须处理,否则代码根本无法通过
2、分类
a.出现异常直接抛出去给调用者,调用者也继续抛出去。
异常处理方式1 —— throws
throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理。
这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。
抛出异常格式:
方法 throws 异常1 ,异常2 ,异常3 ..{
}
规范做法:
方法 throws Exception{
}
//代表可以抛出一切异常.
b. 出现异常自己捕获处理,不麻烦别人。
异常处理方式2 —— try…catch…
监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。
这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行。
格式:
try{
// 监视可能出现异常的代码!
}catch(异常类型1 变量){
// 处理异常
}catch(异常类型2 变量){
// 处理异常
}...
建议格式:
try{
// 可能出现异常的代码!
}catch (Exception e){
e.printStackTrace(); // 直接打印异常栈信息
}
Exception可以捕获处理一切异常类型!
c. 前两者结合,出现异常直接抛出去给调用者,调用者捕获处理。
异常处理方式3 —— 前两者结合
方法直接将异通过throws抛出去给调用者
调用者收到异常后直接捕获处理。
3、异常处理的总结
在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理。
实际应用中,只要代码能够编译通过,并且功能能完成,那么每一种异常处理方式似乎也都是可以的。
六、运行时异常的处理机制
1、运行时异常的处理形式
运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以。
按照规范建议还是处理:建议在最外层调用处集中捕获处理即可。
七、异常处理使代码更稳健的案例
1、需求
键盘录入一个合理的价格为止(必须是数值)。
2、分析
定义一个死循环,让用户不断的输入价格。
3、代码
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true){
try {
System.out.println("请您输入商品价格:");
String s = sc.nextLine();
//转换成double类的价格
double d = Double.valueOf(s);
//判断价格是否大于0
if (d > 0){
System.out.println("商品价格为:"+d);
break;
}else {
System.out.println("请您输入正数价格!");
}
} catch (NumberFormatException e) {
System.out.println("不好意思,您输入格式有误。");
}
}
}
4、结果
八、自定义异常
1、自定义异常的必要?
Java无法为这个世界上全部的问题提供异常类。
如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了。
2、自定义异常的好处:
可以使用异常的机制管理业务问题,如提醒程序员注意。
同时一旦出现bug,可以用异常的形式清晰的指出出错的地方。
3、自定义异常的分类
a.自定义编译时异常
定义一个异常类继承Exception。
重写构造器。
在出现异常的地方用throw new 自定义对象抛出。
作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!
b.自定义运行时异常
定义一个异常类继承RuntimeException。
重写构造器。
在出现异常的地方用throw new 自定义对象抛出!
作用:提醒不强烈,编译阶段不报错!!运行时才可能出现!!