(十八)异常处理及自定义异常

概念

        所谓异常,就是代码发生错误导致无法运行。

分类

        异常主要分为两类,一类是Error,一般是硬件导致的问题。一类是Exception,是软件导致的问题

体系

        Throwable

                Error(错误)

                Exception(异常)

                        CheckedException(检查时异常,一般是语法有问题,在编译代码时产生)

                        RuntimeExcetion(运行时异常,逻辑有问题,在运行过程中产生)

常见的异常

        1.NullPointerException 空指针异常,一般是调用某个对象中的方法或属性,但这个对象是null,会导致空指针异常.

public class Test {
    public static void main(String[] args) {
        String str = null;
        str.trim();
    }
}

         2.ArithmeticException算法异常,一般是我们的数学公式有问题,如10/0;

public class Test{
    public static void main(String[] args){
        System.out.println(10 / 0);
    }
}

         3.IndexOutOfBoundsException下标越界,在使用数组、集合等有下标的存储方式时,使用超出数组或集合最大下标的下标进行操作就会导致下标越界。

public class Test{
    pulic static void main(String[] args){
        int[] arr = {1,2};
        //最大下标是1;
        arr[2] = 0;
    }
}

        4.ClassCastException,类型转换异常,在父类对象转子类对象时,如果没有确认要转换的对象是不是子类对象就进行强制转换 ,很容易产生这种异常。

public class Test{
    public static void main(String[] args){
        Integer i = new Integer(10);
        //子类对象转父类对象没有风险,可以自动转换。
        Object o = i;
        //父类对象转子类对象是有风险的,这个风险就是类型转换异常。‘
        String str = (String) o;
    }
}

异常的传递

        在实际开发中,我们需要使用到大量的第三方工具,在使用过程中必然是经过层层调用的,如果在使用工具的过程中出现了错误,那么将会将错误产生的地方以及调用这处代码的地方一层层列出,直到最外层我们自己实际调用的地方。

public class Test {
    public static void main(String[] args) {
        a();
    }

    private static void a() {
        b();
    }
    static void b(){
        c();
    }
    static void c(){
        System.out.println(10 /0);
    }

}

        如上述代码,我们在经过多重调用方法之后,产生了ArithmeticException异常,在报错显示中会显示多个函数的位置。最上面一层是异常发生的代码,最下面一行是我们最外层调用的地方。一般就是由于我们在实际编码时不了解源码的使用说明,在最外层调用时传入了错误的参数或者错误的值导致的。

异常产生的后果

        异常产生的后果其实很简单,就是程序崩溃,程序停止运行。

异常的处理

        处理异常的方式主要有两种,一种是声明\抛出异常;

1.throws throw

        throws为声明异常,定义位置在方法上,其主要语法是

/*
    访问权限修饰符 修饰符 返回值类型 变量名(形参列表) throws 异常类型1,异常类型2{
        方法体
    }
*/
public static void main(String[] args) throws ArithmeticException{
    div();
}

public static void div() throws ArithmeticException{
    System.out.println(10 / 0);
}

        这种处理异常的方式就是只抛出不处理,就类似于我们去医院看病,医生只是帮我们做了检查,告诉我们身体出现了什么问题,但是这个病该怎么治,医生并没有说,而是等待我们找下一个医生去解决,如果我们找到下一个医生还是使用throws抛出,就相当于这个问题还没有解决,仍然存在,让我们再去等待下一个医生。

        我们在定义方法div的时候很清楚的知道10/0是会产生异常的,但是我们不处理,我们把这个问题抛出,等待下一个调用我们这个方法的人去处理。如到了main函数还不处理,只是抛出的话,就会将异常传递给JVM,而JVM处理异常就只有一种方法——程序崩溃,结束运行。所以我们尽量不要把异常抛给JVM,在实际调用时尽量处理异常。

        throw是抛出异常,在语法上和throws有一点小区别,throw是抛出异常对象,如:

public class Test{
    public static void main(String[] args) throws ArithmeticException{
        div(0);
    }

    public static void div(int num) throws ArithmeticException{
        if (num == 0) throw new ArithmeticException();
        System.out.println(10 / num);
    }
}    

        当我们在调用这个div方法时,如果传入了0,就会抛出这个异常

        如果我们抛出异常只是用了throw,并没有用throws。如

public class Test{
    public static void main(String[] args){
        div(0);
    }

    public static void div(int num){
        if (num == 0) throw new ArithmeticException();
        System.out.println(10 / num);
    }
}    

         这样的处理方式就相当于我们去医院看病,医生知道了我们得的什么病,但是医生不说。。。

        我们正常调用第三方工具时并不会去查看源码,所以如果出现这种问题,开发工具没有提示,很容易就会导致程序崩溃。

try catch

        之前的throw 和 throws只是将问题抛出,并没有解决问题,如果产生了异常,程序还是会崩溃,try catch 就是解决问题的,语法:

/*
    try{
        可能会产生异常的代码
    }catch(异常类型1 变量名){
        当try中的代码产生异常1时,执行此处代码
    }catch(异常类型2 变量名){
        当try中的代码产生异常2时,执行此处代码
    }finally{
        此处代码无论try中的代码会不会产生异常,都会执行此处。
    }
*/
public class Test{
    public static void main(String[] args){
        try{
            div(0);
            System.out.println("div之后,try内部的代码");
        }catch(ArithmeticException err){
            System.out.println("不能传入0");
        }
        System.out.println("try catch 之外的代码");
    }

    public static void div(int num) throws ArithmeticException{
        if (num == 0) throw new ArithmeticException();
        System.out.println(10 / num);
    }
}    

        当try中的代码产生了我们预期的异常之后,程序并不会崩溃,而是停止执行异常代码之后,在try中的代码,去执行catch中对应错误类型的代码,之后执行try catch后面的代码。这样就解决了我们产生异常后程序崩溃的问题。

        注意:

  • catch可以有多个
  • 处在上方的catch期望的异常不能是下面catch期望的异常的父类,上面的异常类型必须小于或等于下面的异常。

自定义异常

        jvm给我们提供的异常是有限的,而且有时我们根据制定的规则去规定属于我们当前项目特有的异常,这种情况下就需要我们自定义异常:

步骤:

  1. 自定义一个类
  2. 使这个类继承于Exception类。
  3. 创建无参构造和有参构造(String),有参构造中输入的内容就是产生异常之后的提示内容。
public class Test {
    public static void main(String[] args) {
        try {
            div(0);
        } catch (ZeroException err) {
            System.out.println(err);
        }
        System.out.println("try catch 之外的代码");
    }

    public static void div(int num) throws ZeroException {
        if (num == 0) throw new ZeroException("除数不能为0");
        System.out.println(10 / num);
    }
}

class ZeroException extends Exception {
    public ZeroException() {
        super();
    }

    public ZeroException(String str) {
        super(str);
    }
}

        如果没有处理异常,而是选择了抛出,最终的效果就是:

public class Test {
    public static void main(String[] args) throws ZeroException {
        div(0);
    }

    public static void div(int num) throws ZeroException {
        if (num == 0) throw new ZeroException("除数不能为0");
        System.out.println(10 / num);
    }
}

class ZeroException extends Exception {
    public ZeroException() {
        super();
    }

    public ZeroException(String str) {
        super(str);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值