Java中的异常机制

异常的概述

  • 在Java中,对于遇到的问题,有一个类来描述:Throwable,它是所有异常或者错误的父类;
  • 对于一般性的问题使用:Exception 类来描述;
  • 严重性问题或者错误使用:Error 类描述;

异常继承图解
在这里插入图片描述

运行期异常

  • 交由Java默认处理运行期异常,使用捕获异常可以使虚拟机程序不退出,后续代码继续执行
  • 多种运行期异常情况使用多个catch来捕获异常
  //多种运行期异常情况使用多个catch来捕获异常,由于异常具体也不清楚因此最后一个捕获异常要使用exception来捕获其他所有异常并且放在最后,exception是所有运行期异常的父类,使用它就可以捕获到所有的异常
        int a = 1;
        int b = 0;
        int arr[] = null;
        try {
          System.out.println(arr[3]);
            System.out.println(a / b);

        } catch (ArithmeticException e) {
            System.out.println("指定捕获的异常: " + e);
        }
        // Exception捕获所有的异常,必须放在最后写
        catch (Exception e) {
            System.out.println("Exception捕获所有的异常: " + e);
        }
        System.out.println("后续代码继续运行");
  int arr1[] = null;
        //没有捕获到正确的异常,就会将异常交给JVM,输出异常信息并停止后续代码执行。
        try {//角标越界异常,但捕获数学异常
            System.out.println(arr[3]);

        } catch (ArithmeticException e) {
            System.out.println("捕获数学异常: " + e);
        }
        //输出异常信息,停止后续代码执行。
        System.out.println("后续代码继续运行");

finally与return

  • 不管try里面的代码有没有遇到异常,finally里面的代码一定会执行,一般我们会把一些善后收尾的代码写在里面,比如释放资源;finally块不是必须要写的,可以写也可以不写,根据自己的需求来设计程序;
  • 即使存在return关键字,finally块里面的代码仍然执行,并且是在return关键字之前执行,否则的话就不会输出了;
  • 如果是程序正常退出,终止当前正在运行的 Java 虚拟机,finally块里面的代码也就不会执行了;
   //finally里面做一些善后,收尾工作,比如释放资源。
        try{
            System.out.println(1/0);//异常为: ArithmeticException
            //此时 由JVM捕捉到的 ArithmeticException异常会打印异常,执行finally的代码,再退出程序
            System.out.println("此处代码不会执行");
            //catch一个角标越界异常
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
            //没有捕获到正确的异常,但是要执行finally的语句
        }finally {
            System.out.println("无论是否遇到异常,都要执行的语句");
        }
    }

执行结果:
在这里插入图片描述

编译期异常

编译期异常的处理的两种方式
在这里插入图片描述

是指非RuntimeException及其子类,编译期异常必须处理,否则程序无法运行;

public static void main(String[] args) throws ParseException {
  //编译期异常,处理方式1:throws抛出异常给JVM处理;
        String dateStr = "2017-01-01";
        parseDate(dateStr);//抛给JVM
        System.out.println("next code");
        
        //方式2:try cath自己捕获处理
        try {
            parseDate(dateStr);
        } catch (ParseException e) {
            System.out.println(e);
        }
        //编译期异常处理之后不影响后续代码
        System.out.println("next code");
}

处理异常的时机选择

public class MyTest {
    public static void main(String[] args) throws ParseException {
        String sDate = "2012-08-==23";
        dateParse(sDate);
        /*解析异常
        null*/
    }

    private static void dateParse(String sDate) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        date = format.parse(sDate);
        System.out.println(date);
    }
}

  • 我们把错误向上抛出,一层甩给一层,上面的代码里面,自定义方法抛给main(),如果main()还不想处理,仍然向上抛出,这时候只能是Java虚拟机来使用默认的方式进行处理;
  • 一般来说,到了main()就不再继续抛出了,而是选择自己捕获处理,因为自己处理的方式友好;
  • 还有就是假如我们上面的解析日期的方法写在工具类里面,这时候异常选择向上抛出,谁调用,谁解决,因为别人的处理异常的方式有可能和你的不一样;
  • 对于异常的处理,不要做空处理(也就是catch块里面的代码不能为空),哪怕是一句简单的提示语句;

异常里面的几个方法

String getMessage()——返回此 throwable 的详细消息字符串;
StackTraceElement[] getStackTrace()——提供编程访问由 printStackTrace() 输出的堆栈跟踪信息;
void printStackTrace()——将此 throwable 及其追踪输出至标准错误流;虚拟机默认调用该方法打印堆栈信息;

public class MyTest {
    public static void main(String[] args) {
        String sDate = "2012-08-==23";
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(sDate);
        } catch (ParseException e) {
            System.out.println(e.getMessage());
            //Unparseable date: "2012-08-==23"
            System.out.println(e.getStackTrace());
            //[Ljava.lang.StackTraceElement;@60e53b93
            e.printStackTrace();
            /*java.text.ParseException: Unparseable date: "2012-08-==23"
            at java.text.DateFormat.parse(DateFormat.java:366)
            at org.westos.demo4.MyTest.main(MyTest.java:13)*/
        }
        System.out.println(date);
    }
}

关键字throw与throws的区别

  • 相同点:两者都可以进行异常的抛出;
  • 不同点:throws用在方法的声明上,throw用在方法的内部;
    throws抛出来的是一个类,而throw则是new出来的对象;
private static double show(int a, int b) {
        double r = 0;
        if (b == 0) {
            //   throw 方法内部进行异常抛出,让程序直接结束
            throw new ArithmeticException("除数为0 程序接收");
        } else r = a / b;
        return r;
    }

自定义异常

  • 在我们进行实际的开发时,会遇到各种异常,Java给我们提供的异常类,并不能完全描述我们遇到的异常;比如你在做银行类的项目,可能遇到余额不足的问题,这时候程序检测到这个异常,就需要抛出异常,然程序终止;Java没有提供给我们这样的异常,还有诸如人脸识别的异常、指纹识别的异常等,业务需要这些异常,我们可以自定义它们;
  • 如何把自定义异常纳入异常体系当中?自定义的异常都需要继承运行期异常类;

测试类:

public class Mytest {
    private static double money;

    public static void main(String[] args) {
        money=100;
        Scanner scanner = new Scanner(System.in);
        System.out.println("input take money: ");
        double v = scanner.nextDouble();
        qukuan(v);

    }

    private static void qukuan(double v) {
        if (money>=v)
        money-=v;
        else throw new NoMoneyException("余额不足异常");
    }
}

自定义异常类:

public class NoMoneyException extends RuntimeException {
    public NoMoneyException(String msg) {
     super(msg);
    }
}

使用异常需要注意的问题

子类在重写父类的方法时,如果父类没有抛出异常,子类也不能抛出异常,这时候,一旦有异常,你就内部消化,使用try-catch块处理;

public class Fu {
    public void show() {
        String sDate = "2012-08-==23";
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(sDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        System.out.println(date);
    }

}

class Zi extends Fu{
    @Override
    public void show() {
        System.out.println("这是子类~");
    }
}

子类不能抛出父类没有抛出过的异常;
子类抛出的异常必须是和父类异常一样或者是父类异常的子类,不能是基类;

在这里插入图片描述

父类抛出异常,子类可以不抛出;

public class Fu {
    public void show() throws ParseException {
        String sDate = "2012-08-==23";
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        date = format.parse(sDate);
        System.out.println(date);
    }
}

class Zi extends Fu{
    @Override
    public void show() {
        try {
            super.show();
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值