异常处理详解

异常概述

什么是异常?

异常是程序在“编译”或者“执行”的过程中可能出现的问题,注意:语法错误不算在异常体系中。 比如:数组索引越界、空指针异常、 日期格式化异常,等。

为什么要学习异常?

异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止.

研究异常并且避免异常,然后提前处理异常,体现的是程序的安全, 健壮性。

问题体系

Error: 错误,系统级别问题、JVM退出等,代码无法控制。 

Exception:java.lang包下,称为异常类,它表示程序本身可以处理的问题.

         RuntimeException及其子类:运行时异常,编译阶段不会报错,运行时可能出现的错误,例如:空指针异常,数组索引越界异常。

        除RuntimeException之外所有的异常:编译时异常,编译期必须处理的,否则程序不能通过编译。 (日期格式化异常)。

编译时异常和运行时异常的区别

运行时异常

定义:直接继承自RuntimeException或者其子类,编译阶段不会报错,运行时可能出现的错误。

示例:

数组索引越界异常: ArrayIndexOutOfBoundsException。

空指针异常 : NullPointerException,直接输出没有问题,但是调用空指针的变量的功能就会报错。

数学操作异常:ArithmeticException。

类型转换异常:ClassCastException。

数字转换异常: NumberFormatException。

运行时异常:一般是程序员业务没有考虑好或者是编程逻辑不严谨引起的程序错误, 自己的水平有问题!

编译时异常

定义:

继承自Exception的异常或者其子类且不是RuntimeException或者其子类的异常,编译阶段就报错,必须处理,否则代码不通过。

示例:

编译时异常的作用是什么:

        是担心程序员的技术不行,在编译阶段就爆出一个错误, 目的在于提醒不要出错!

        编译时异常是可遇不可求。遇到了就遇到了呗。

异常的默认处理流程

/**
     目标:异常的产生默认的处理过程解析。(自动处理的过程!)
    (1)默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException。
    (2)异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机。
    (3)虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。
    (4)直接从当前执行的异常点干掉当前程序。
    (5)后续代码没有机会执行了,因为程序已经死亡。

    小结:
         异常一旦出现,会自动创建异常对象,最终抛出给虚拟机,虚拟机
         只要收到异常,就直接输出异常信息,干掉程序!!

         默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡!
 */
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;
        System.out.println(c);
    }
}

编译时异常的处理机制

三种:

出现异常直接抛出去给调用者,调用者也继续抛出去。  

出现异常自己捕获处理,不麻烦别人。  

前两者结合,出现异常直接抛出去给调用者,调用者捕获处理。

异常处理方式1 —— throws

throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理。

这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。

抛出异常格式:

方法 throws 异常1 ,异常2 ,异常3 ..{ }

规范做法:方法 throws Exception{ },代表可以抛出一切异常,因为只要发生其中一个异常,其他异常就不会发生。

异常处理方式2 —— try…catch…

监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。 这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行。

格式:

   try{
       // 监视可能出现异常的代码!
   }catch(异常类型1 变量){
       // 处理异常
   }catch(异常类型2 变量){
       // 处理异常
   }
   ...

建议格式: 

try{
    // 可能出现异常的代码!
}catch (Exception e){
    e.printStackTrace(); // 直接打印异常栈信息
}

//Exception可以捕获处理一切异常类型!

异常处理方式3 —— 前两者结合

 方法直接将异常通过throws抛出去给调用者, 调用者收到异常后直接捕获处理。

运行时异常的处理机制

运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以。

按照规范,建议还是处理:建议在最外层调用处集中捕获处理即可。 

异常处理的总结

1、在开发中按照规范来说第三种方式是最好的:底层的异常抛出去给最外层,最外层集中捕获处理。

2、实际应用中,只要代码能够编译通过,并且功能能完成,那么每一种异常处理方式似乎也都是可以的。

异常处理使代码更稳健的案例

需求  键盘录入一个合理的价格为止(必须是数值,值必须大于0)。

分析 定义一个死循环,让用户不断的输入价格。

public class Test2 {
    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 (Exception e) {
                System.out.println("用户输入的数据有毛病,请您输入合法的数值,建议为正数~~");
            }
        }
    }
}

自定义异常

自定义异常的必要?Java无法为这个世界上全部的问题提供异常类。 如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了。

自定义异常的好处: 可以使用异常的机制管理业务问题,如提醒程序员注意。 同时一旦出现bug,可以用异常的形式清晰的指出出错的地方。

分类

1、自定义编译时异常        

定义一个异常类继承Exception.  

重写构造器。  

在出现异常的地方用throw new 自定义对象抛出,

作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!

2、自定义运行时异常

定义一个异常类继承RuntimeException.

重写构造器。

在出现异常的地方用throw new 自定义对象抛出!

作用:提醒不强烈,编译阶段不报错!!运行时才可能出现!!

示例

public class ExceptionDemo {
    public static void main(String[] args) {
//        try {
//            checkAge(-34);
//        } catch (ItheimaAgeIlleagalException e) {
//            e.printStackTrace();
//        }

        try {
            checkAge2(-23);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void checkAge2(int age)  {
        if(age < 0 || age > 200){
            // 抛出去一个异常对象给调用者
            // throw :在方法内部直接创建一个异常对象,并从此点抛出
            // throws : 用在方法申明上的,抛出方法内部的异常
            throw new ItheimaAgeIlleagalRuntimeException(age + " is illeagal!");
        }else {
            System.out.println("年龄合法:推荐商品给其购买~~");
        }
    }

    public static void checkAge(int age) throws ItheimaAgeIlleagalException {
        if(age < 0 || age > 200){
            // 抛出去一个异常对象给调用者
            // throw :在方法内部直接创建一个异常对象,并从此点抛出
            // throws : 用在方法申明上的,抛出方法内部的异常
            throw new ItheimaAgeIlleagalException(age + " is illeagal!");
        }else {
            System.out.println("年龄合法:推荐商品给其购买~~");
        }
    }
}
public class ItheimaAgeIlleagalException extends Exception{
    public ItheimaAgeIlleagalException() {
    }

    public ItheimaAgeIlleagalException(String message) {
        super(message);
    }
}

 

public class ItheimaAgeIlleagalRuntimeException extends RuntimeException{
    public ItheimaAgeIlleagalRuntimeException() {
    }

    public ItheimaAgeIlleagalRuntimeException(String message) {
        super(message);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值