java基础——异常

1 异常的概述、体系

1.1 什么是异常?

  • 异常是程序在编译或运行中可能出现的问题。
  • 比如:数组索引越界、空指针异常、日期格式化异常等
  • 异常一旦出现,如果没有及时处理,程序就会退出JVM虚拟机而终止。
  • 研究异常并且避免异常,然后提前处理异常,体现的是程序的安全、健壮性
public class ExceptionDemo {
    public static void main(String[] args){
        int[] arr = {1,2,3};
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        //数组越界异常
        System.out.println(arr[3]);
        System.out.println("___________上面错误,这里不会被显示________");

    }
}

会出现如下结果(程序终止并且抛出异常)
在这里插入图片描述


1.2 异常体系

Error
系统级别问题,JVM退出等,代码无法控制
Exception:java.lang包下,称为异常类,它表示程序本身可以处理的问题。

  • RuntimeException及其子类:运行时异常,编译阶段不会报错。
  • 除RuntimeException之外的所有异常:编译时异常,这种在编译期必须处理,否则程序不能通过编译。(写代码阶段就会报错)

在这里插入图片描述


1.3 运行时异常

运行时异常示例:

  • 数组索引越界异常:ArrayIndexOutofBoundsException
  • 空指针异常:NullPointerException,直接输出没有问题,但是调用空指针的变量功能就会报错
  • 数学操作异常:ArithmeticException
  • 类型转换异常:ClassCastException
  • 数字转换异常:NumberFormatException
    运行时异常:一般是程序员技术不行导致的
public class ExceptionDemo {
    public static void main(String[] args){
        String name = null;
        System.out.println(name);
        // 这里会出现空指针异常
        int len = name.length();
        System.out.println(len);
    }
}

在这里插入图片描述

2 异常的默认处理流程

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

2.1 编译时异常的处理形式

  • 1,出现异常直接抛出给调用者,调用者也抛出去
  • 2,出现异常自己捕获处理,不麻烦别人
  • 3,前两者结合,出现异常直接抛出去给调用者,调用者捕获处理

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

如果有多个异常可以选择throws 异常1,异常2,异常3(出问题时其实只抛出一个)
也可直接throws Exception(Exception是其他的父类,类型更高)
这个方式不好,如果异常最终抛给JVM虚拟机会导致程序死亡
如下图所示,出现编译时异常 出现
抛出异常给调用者,那么方法就不会再报错
在这里插入图片描述
调用者继续抛出异常给虚拟机。虚拟机会把程序干掉。
在这里插入图片描述


方法2

try…catch…

  • 监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理
  • 这个方法还行,发生异常的方法直接独立处理异常,程序继续往下执行
try{
//可能会出现异常的代码
}catch(异常类型1 变量){
//处理异常
}catch(异常类型1 变量){
//处理异常
}...
    public static void parseTime(String date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-dd");
        Date d = null;
        //对异常1的处理
        try {
            d = (Date) sdf.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println(d);
        
        //对异常2的处理
        try {
            InputStream is = new FileInputStream("E:/bucunzai.jpg");

        }catch (Exception e){
            e.printStackTrace();
        }
    }

当然也可以两个放在一起抛出,这时程序会抛出第一个异常然后程序结束
这个方法更好,如果多个异常时更省力

public class ExceptionDemo {
    public static void main(String[] args)  {
    parseTime("2022-03-05");
    }

    public static void parseTime(String date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-dd");
        try {
            Date d = null;
            d = (Date) sdf.parse(date);
            System.out.println(d);
            InputStream is = new FileInputStream("E:/bucunzai.jpg");
        }catch (Exception e){
            e.printStackTrace();//打印异常栈信息
        } 
    }

方法3(推荐!!!)

前两者结合

  • 方法直接将异常throws给调用者
  • 调用者捕获并处理异常
    (这个方法更好,因为调用者更希望知道下级的情况,而不是下级自己直接处理但是并不汇报)
public class ExceptionDemo {
    public static void main(String[] args)  {
    //调用者捕获并且处理异常
    try {
        parseTime("2022-03-05");

    }catch (Exception e){
        e.printStackTrace();
    }
   
    }
    //方法抛出异常
    public static void parseTime(String date) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-dd");

        Date d = null;
        d = (Date) sdf.parse(date);
        System.out.println(d);
        InputStream is = new FileInputStream("E:/bucunzai.jpg");
    }
}

2.2 运行时异常的处理机制

  • 运行时异常在编译阶段不会报错,编译阶段不处理也可以
  • 按照规范建议还是处理:建议在最外层调用处集中捕获处理即可
    注:运行时异常不用自己加throws 自己就会抛出(运行中自动抛出)
public class ExceptionDemo {
    public static void main(String[] args)  {
        System.out.println("开始,,,,,,,");
        //调用者处理异常 不影响后续程序的执行
        try {
            chu(10,0);

        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("结束,,,,,,");
    }
    public static void chu(int a, int b){ //throws Exception
        System.out.println(a);
        System.out.println(b);
        //这里分母不应该为零,可能会出现RuntimeException
        int c = a / b;
        System.out.println(c);
    }

在这里插入图片描述

3 异常案例

键盘录入一个合理的价格为止(必须是数值,值必须大于0)
定义一个死循环,让用户不断输入价格

public class Test {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while (true){
            System.out.println("请输入合法的价格:");
            String priseStr = sc.nextLine();
            //如果用户输入的不是数而是乱七八糟的东西,那么会导致运行异常程序终止
            double price = Double.valueOf(priseStr);
            if(price > 0 ){
                System.out.println("定价"+price);
                break;
            }else {
                System.out.println("价格必须不小于0");
            }
        }
    }
}

用户如果输入的是不合理的数还行,但是如果输入其他会导致异常

在这里插入图片描述
进行异常处理

        try {
            while (true) {
                System.out.println("请输入合法的价格:");
                String priseStr = sc.nextLine();
                //如果用户输入的不是数而是乱七八糟的东西,那么会导致运行异常程序终止
                double price = Double.valueOf(priseStr);
                if (price > 0) {
                    System.out.println("定价" + price);
                    break;
                } else {
                    System.out.println("价格必须不小于0");
                }
            }
        }catch (Exception e){
            System.out.println("请您输入合法的价格");
        }

这时就不会终止程序而是继续提示重新输入

(这里其实还有点问题,抛出异常后只能保证程序不报错结束,但是循环不在继续,实际上是无法继续判断的!!!)

在这里插入图片描述

4 自定义异常

  • java无法为所有异常提供异常类
  • 企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类
  • 使用异常类机制管理业务问题,如提醒程序员注意
  • 一旦出现bug,可以用异常的方式清晰的指出出错的地方

自定义异常的方法

1 自定义编译时异常
  • 定义一个异常类继承Exception
  • 重写构造器
  • 在异常出现的地方用 throw new自定义对象抛出
    下面是自定义的年龄非法输入的类
/**
 * 自定义年龄异常   0-200 之外的都算作异常
 */
public class AgeIlleagalException extends Exception{
    public AgeIlleagalException() {
    }
    public AgeIlleagalException(String message){
        super(message);
    }
}

使用这个异常类来检查异常

public class AgeCheck {
    public static void main(String[] args){
        //这时这里就会直接报错,提醒程序员出问题了
        CheckAge(300);//Error!!!
    }
    public static void  CheckAge(int age) throws AgeIlleagalException {
        if(age<0 || age>200){
           //抛出异常  如果这里只是提醒,则不知道问题出在哪里
            //throws:用在方法申明上的,抛出方法内部的异常
            //throw:在方法内部查找一个异常对象,并且抛出
            throw new AgeIlleagalException("年龄有问题");
        }else {
            System.out.println("年龄是"+ age);
        }
    }
}

然后就可以捕获异常,程序不会终止

    public static void main(String[] args) throws AgeIlleagalException{
        //这时这里就会直接报错,提醒程序员出问题了
        try {
            CheckAge(300);
        }catch (AgeIlleagalException e){
            e.printStackTrace();
        }
    }

在这里插入图片描述


2 自定义运行时异常
  • 定义一个异常类继承RuntimeException
  • 重写构造器
  • 在出现异常的地方用throw new自定义对象抛出
    作用:这个的提醒并不强烈,编译阶段不报错!!运行时才报错 编译时异常经常打扰程序员,非必要不定义编译异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值