什么是异常
异常时程序在“编译”或者“执行”的过程中可能出现的问题:
注意:语法错误不算是异常体系中
比如:数组索引越界、空指针异常,日期格式化异常等
为什么要学习异常
- 异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止
- 研究异常并且避免异常,然后提前处理异常,体现的是程序的安全,健壮性
public static void main(String[] args) {
int[] arr={10,20,40};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
System.out.println("--------程序截至-------");//这个是不会打印的,因为数组越界
}
Error:
- 系统级别问题,JVM退出等,代码无法控制。
Exceptin: java.lang包下,称为异常类,他表示程序本可以处理的问题
RuntimeException及其子类: 运行时异常,编译阶段不会报错。(空指针异常,数组索引越界异常)
除RuntimeException之外的所有异常: 编译时异常,编译器必须处理的,否则程序不能通过编译。(日期格式化异常)
编译异常和运行时异常
简单来说
- 编译异常就是在编译的时候出现的异常
- 运行异常就是在运行是时出现的异常
常见运行时异常
运行时异常
- 直接继承自RuntimeException或者子类,编译阶段不会报错,运行时异常可能出现的错误。
运行时异常示例
- 数组索引越界异常:ArrayIndexOutBoundsException
- 空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。
- 数字操作异常:ArithmeticException
- 类型转换异常:ClassCasrException
- 数字转换异常:NumberFormaExcception
运行时异常:一般时程序员业务没有考虑好或者时编程逻辑不严谨引起的程序错误
public static void main(String[] args) {
//数组索引越界异常:ArraIndexOutOfBoundException
int[] arr={1,2,3};
//System.out.println(arr[3]);//运行出错,程序终止
//空指针异常:NullPointerException直接输出没有问题,但是调用空指针的变量的功能就会报错
String name=null;
System.out.println(name);//null
//System.out.println(name.length());//运行出错,程序终止
//类型转换异常:ClassCastException
Object o=23;//如果是'23'就不会报错
//String s=(String)o;//运行出错程序终止
//数字操作异常:ArithmeticException
//int c=10/0;
//数字转换异常:NumberFormatException
String number="23aabbc";
Integer it=Integer.valueOf(number);
System.out.println(it);
System.out.println("程序结束");
}
编译时异常
- 不是RuntimeException或者其子类的异常, 编译阶段就报错,必须处理,否则代码不通过。
在Date d=sdf.parse(date);日期解析异常。
public static void main(String[] args) throws ParseException {
String date="2015-01-12 10:23:21";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d=sdf.parse(date);
}
编译时异常的作用
- 是担心程序员的技术不行,在编译阶段就爆出一个错误,目的在于体系不要出错
- 编译时异常时可遇不可求的。遇到了就遇到了
异常的默认处理流程
- 默认会初心异常的代码那里创建一个异常对象:ArthmeticException。
- 异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机
- 虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据
- 直接从当前执行的异常点干掉当前程序
- 后续代码没有机会执行了,因为程序以及死亡
默认异常处理机制:默认的异常处理机制并不好,一旦真的出现异常程序立即死亡!
编译时异常的处理机制
编译时异常时编译阶段救出做,所以必须处理,否则代码根本无法通过
编译时异常的处理形式由三种:
- 出现异常直接抛出去给调用者,调用者以继续抛出去
- 出现一号仓自己捕获吹,不麻烦别人
- 前两者结合,出现异常直接跑出去给调用者,调用者捕获处理
异常处理方式1——throws
- throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理
- 这种方式并不好,发生异常的方法不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡
抛出异常格式
方法 throws 异常1,异常2,异常3...{
}
规范做法:
方法 throws Exception{
}
异常处理方式2——try…catch…
- 监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理
格式
try{
//监视可能出现异常代码
}catch(异常类型1 变量){
//处理异常
}catch(异常类型2 变量){
//处理异常
}
建议格式
try{
//可能出现异常的代码!
}catch(Exception e){
e.printStackTrace()//直接答应异常栈信息
}
Exception可以捕获处理一些异常类型!
public class ExceptionDemo {
/**
* 程序开始....
* 出现了解析时间异常处理,走点心
* 您的文件根本就没有,不要骗我哦
* 程序结束
*/
public static void main(String[] args){
System.out.println("程序开始....");
parseTime("2011/11-11 11:11:11");
System.out.println("程序结束");
}
private 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);
} catch (ParseException e) {
//解析出问题
System.out.println("出现了解析时间异常处理,走点心");
}
try {
InputStream is=new FileInputStream("E/shuaige.jpg");
} catch (FileNotFoundException e) {
System.out.println("您的文件根本就没有,不要骗我哦");
}
}
}
异常处理方式3——前两者结合
- 方法直接将异通过throws抛出去给调用者
- 调用者收到异常后直接捕获处理。
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("程序结束");
}
private 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);
System.out.println("出现了解析时间异常处理,走点心");
InputStream is=new FileInputStream("E/shuaige.jpg");
}
编译异常处理总结
- 在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理
- 实际应用中,只要代码能够编译通过,并且功能能完成,那么每一种异常处理凡是似乎也都是可以的
运行时异常处理机制
- 运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以
- 按照规范建议还是处理:建议在最外层调用集中捕获处理即可
异常处理使代码更稳定的案例
需求:
键盘录入一个合理的价格为止(必须是数值,值必须大于0)
分析
定义一个死循环,然用户不断地输入价格
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while (true){
try {
System.out.println("请输入合法的价格:");
String priceStr=sc.nextLine();
//转换成double
double price=Double.valueOf(priceStr);
//判断价格是否大于0
if(price>0){
System.out.println("定价"+price);
break;
}else{
System.out.println("价格必须时正确的");
}
} catch (NumberFormatException e) {
System.out.println("用户输入的数据有毛病");
}
}
}
自定义异常
- java无法为全部的异常一共异常类
- 如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类
自定义异常的好处: - 可以使用异常的机制管理业务问题提,如提程序员注意
- 同时一旦出现BUG,可以用异常的形式清晰的指出出错的地方
public class ExceptionDemo {
public static void main(String[] args) {
try {
checkAge(24);
} catch (ageIlleagaException e) {
e.printStackTrace();
}
}
public static void checkAge(int age) throws ageIlleagaException {
if(age<0||age>200){
//抛出去一个异常给调用者
//throw:在方法内部直接创建一个异常对象并抛出
//throws:用在方法申明上,抛出方法内部的异常
throw new ageIlleagaException(age+" is illeagal!");
}else {
System.out.println("年龄合法:推荐商品给其购买~~");
}
}
}
/**
* 自定义的编译时异常
* 1.继承Exception
* 2.重写构造器
*/
public class ageIlleagaException extends Exception{
public ageIlleagaException() {
}
public ageIlleagaException(String message) {
super(message);
}
}
自定义异常的分类
1.自定义编译时异常
- 定义一个异常类继承Exception,
- 重写构造器
- 在出现异常的地方用throw new自定义对象抛出
- 作用:编译时异常时编译阶段就报错,提醒更加强烈,一定需要处理
2.自定义运行时的异常 - 定义一个异常类继承RuntimeException
- 重写构造器
- 在出现异常的地方用throw new 定义对象抛出
作用:提醒不强烈,编译杰顿不报错,运行时才可能出现
public class ExceptionDemo {
public static void main(String[] args) {
// try {
// checkAge(24);
// } catch (ageIlleagaException e) {
// e.printStackTrace();
// }
try {
checkAge(23);
} catch (ageIlleagaException e) {
e.printStackTrace();
}
}
public static void checkAge2(int age){
if(age<0||age>200){
//抛出去一个异常给调用者
//throw:在方法内部直接创建一个异常对象并抛出
//throws:用在方法申明上,抛出方法内部的异常
throw new ageIlleagaRunException(age+" is illeagal!");
}else {
System.out.println("年龄合法:推荐商品给其购买~~");
}
}
public static void checkAge(int age) throws ageIlleagaException {
if(age<0||age>200){
//抛出去一个异常给调用者
//throw:在方法内部直接创建一个异常对象并抛出
//throws:用在方法申明上,抛出方法内部的异常
throw new ageIlleagaException(age+" is illeagal!");
}else {
System.out.println("年龄合法:推荐商品给其购买~~");
}
}
}
public class ageIlleagaRunException extends RuntimeException{
public ageIlleagaRunException() {
}
public ageIlleagaRunException(String message) {
super(message);
}
}