Java-异常篇(带你看懂异常,处理异常,自定义异常)

目录

一、通过if-else解决异常

二、通过try-catch解决异常

 三、异常_多重catch

四、异常的分类:

五、异常_throw和throws的区别

 六、自定义异常


一、通过if-else解决异常

代码演示:

package com.hhf.test01;

import java.util.Scanner;


public class Test {
    public static void main(String[] args) {
        //实现一个功能:键盘录入两个数,求商:
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个数");
        int num1 = sc.nextInt();
        System.out.println("请输入第二个数");
        int num2 = sc.nextInt();
        System.out.println("商:"+num1/num2);
    }
}

运行结果:

 测试过程中发现问题:录入的数据应为int类型,但是录入非int类型数据的时候,出异常

 当除数为时出现异常:

 异常:exception:在程序运行过程中,发生了不正常的现象,阻止了程序的运行,我们称之为发生异常。

通过if-else解决异常:

package com.hhf.test01;

import java.util.Scanner;


public class Test {
    public static void main(String[] args) {
        //实现一个功能:键盘录入两个数,求商:
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个数");
        if(sc.hasNextInt()){//判断输入的是不是整数
            int num1 = sc.nextInt();
            System.out.println("请输入第二个数");
            if(sc.hasNextInt()){
                int num2 = sc.nextInt();
                if(num2 == 0){
                    System.out.println("对不起,除数不能为0");
                }
                else {
                    System.out.println("商:"+num1/num2);
                }
            }else {
                System.out.println("对不起,你录入的不是int类型的数据");
            }
        }else {
            System.out.println("对不起,你录入的不是int类型的数据");
        }
    }
}

 

用if-else堵漏洞的缺点:

(1)代码臃肿,业务代码和处理异常的代码混在一起

(2)可读性差

(3)程序员需要花费大量的精力来维护这个漏洞

(4)程序很难堵住所有的漏洞。

二、通过try-catch解决异常

1. 基于if-else处理异常缺点太多,所以Java中专门出了一个异常处理机制:异常三连” try-catch-finally

2.异常出现了,应该怎么看?

3. 捕获异常 try-catch

package com.hhf.test01;

import java.util.Scanner;

public class Test2 {
    public static void main(String[] args) {
        //实现一个功能:键盘录入两个数,求商:
        try {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第一个数");
            int num1 = sc.nextInt();
            System.out.println("请输入第二个数");
            int num2 = sc.nextInt();
            System.out.println("商:"+num1/num2);
        }catch (Exception ex){
            System.out.println("sorry,程序出错了");
        }
        System.out.println("----谢谢你使用计算器----");
    }
}

原理:把可能出现异常的代码放入try代码块中,然后将异常封装为对象,被catch后面的()中的那个异常对象接收,接收以后:执行catch后面的{}里面的代码,然后try-catch后面的代码,该怎么执行就怎么执行。

详细说一下:

(1)try中没有异常,catch中代码不执行。

(2)try中有异常,catch进行捕获;如果catch中异常类型和你出的异常类型匹配的话:走catch中的代码——》进行捕获;如果catch中异常类型和你出的异常类型不匹配的话:不走catch的代码——》没有捕获成功,程序相当于遇到异常了,中断了,后续代码不执行

注意:

(1)try中如果出现异常,然后用catch捕获成功的话,那么try中后续的代码是不会执行的。

(2)如果catch捕获异常成功,那么try-catch后面的代码该执行还是执行,没有影响

4.catch中如何处理异常:

package com.hhf.test01;

import java.util.Scanner;


public class Test3 {
    public static void main(String[] args) {
        //实现一个功能:键盘录入两个数,求商:
        try {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第一个数");
            int num1 = sc.nextInt();
            System.out.println("请输入第二个数");
            int num2 = sc.nextInt();
            System.out.println("商:"+num1/num2);
        }catch (Exception ex){
            //第一种处理:什么都不写,什么都不做

            //第二种处理:
            //System.out.println("sorry,你的代码出bug了");

            //第三种处理:打印异常信息:
            /*(1)调用toString方法,显示异常的类名(全限定路径)*/
            /*System.out.println(ex);
            System.out.println(ex.toString());*/

            /*(2)显示异常描述信息对应的字符串,如果没有就显示null
            System.out.println(ex.getMessage());*/
            /*(3)显示异常的堆栈信息:将异常信息捕获以后,在控制台将异常的效果给我们展示出来,方便我们查看异常
            ex.printStackTrace();*/
            
            //第四种处理:抛出异常
            throw ex;
        }
        System.out.println("----谢谢你使用计算器----");
    }
}

在什么情况下,try-catch后面的代码不执行?

(1)throw抛出异常的情况

(2)catch中没有正常的进行异常捕获

(3)在try中遇到return

怎么样才能将try-catch后面的代码 必须执行?

只要将必须执行的代码放入finally中,那么这个代码无论如何一定执行

return和finally执行顺序:先执行finally,最后执行return

什么代码会放在finally中呢?

关闭数据库资源,关闭IO流资源,关闭socket资源。

下面这句话,能让finally中的代码不执行

System.exit(0);//终止当前的虚拟机执行

 

package com.hhf.test01;

import java.util.Scanner;


public class Test3 {
    public static void main(String[] args) {
        //实现一个功能:键盘录入两个数,求商:
        try {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第一个数");
            int num1 = sc.nextInt();
            System.out.println("请输入第二个数");
            int num2 = sc.nextInt();
            System.out.println("商:"+num1/num2);

            System.exit(0);//终止当前的虚拟机执行

            return;
        }catch (Exception ex){
            //第一种处理:什么都不写,什么都不做

            //第二种处理:
            //System.out.println("sorry,你的代码出bug了");

            //第三种处理:打印异常信息:
            /*(1)调用toString方法,显示异常的类名(全限定路径)*/
            /*System.out.println(ex);
            System.out.println(ex.toString());*/

            /*(2)显示异常描述信息对应的字符串,如果没有就显示null
            System.out.println(ex.getMessage());*/
            /*(3)显示异常的堆栈信息:将异常信息捕获以后,在控制台将异常的效果给我们展示出来,方便我们查看异常
            ex.printStackTrace();*/

            //第四种处理:抛出异常
            //throw ex;
        }finally {
            System.out.println("----谢谢你使用计算器----");
        }

    }
}

 三、异常_多重catch

  1. try中出现异常以后,将异常类型跟catch后面的类型依次比较,按照代码的顺序进行比对,执行第一个与异常类型匹配的catch语句

  2. 一旦执行其中一条catch语句之后,后面的catch语句就会被忽略了!

  3. 在安排catch语句顺序的时候,一般会将特殊异常放在前面(并列),一般化的异常放在后面。先写子类异常,在写父类异常。

  4. 在JDK1.7以后,异常新处理方式:可以并列用|符号连接:

 

package com.hhf.test01;

import java.util.InputMismatchException;
import java.util.Scanner;


public class Test4 {
    public static void main(String[] args) {
        //实现一个功能:键盘录入两个数,求商:
        try {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第一个数");
            int num1 = sc.nextInt();
            System.out.println("请输入第二个数");
            int num2 = sc.nextInt();
            System.out.println("商:"+num1/num2);

            System.exit(0);//终止当前的虚拟机执行

            return;
        }catch (InputMismatchException ex){
            System.out.println("对不起,你录入的数据不是int数据类型");
        }catch (ArithmeticException ex){
            System.out.println("对不起,除数不可为0");
        }catch (Exception ex){
            System.out.println("对不起,你的程序出现异常了");
        }finally {
            System.out.println("----谢谢你使用计算器----");
        }

    }
}

四、异常的分类:

1.层次结构:

 注意:程序中语法错误,逻辑错误,都不属于上面的error,Exception

2.运行时异常时异常(写代码的时候,不用特意对异常进行处理,在程序运行后,系统自动检测,然后报出异常)如:NullPointerException(空指针异常),ArrayIndexOutOfBoundsException(数组下标越界异常)

package com.hhf.test01;


public class Test5 {
    public static void main(String[] args) {
        //运行时异常
        int[] arr ={1,2,3};
        System.out.println(arr.length);
        /*int[] arr2 = null;
        System.out.println(arr2.length);*/
        System.out.println(arr[10]);
    }
}

检查异常:(防患于未然的效果,在写代码的时候就要对代码的异常进行处理)也是为了代码的健壮性。

 

 

 处理方式1:

package com.hhf.test01;


public class Test6 {
    public static void main(String[] args) {
        //检查异常:
        try {
            try {
                Class.forName("com.msb.test01.Test").newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

 处理方式2:

package com.hhf.test01;


public class Test6 {
    public static void main(String[] args) {
        //检查异常:
        try {
            Class.forName("com.msb.test01.Test").newInstance();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

处理方式3:

package com.hhf.test01;


public class Test6 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //检查异常:
        Class.forName("com.msb.test01.Test").newInstance();
    }
}

五、异常_throw和throws的区别

package com.hhf.test01;

import java.util.Scanner;


public class Test7 {
    public static void main(String[] args) throws Exception {
        //实现一个功能:两个数相除,当除数为0的时候,程序出现异常
        devide();
    }
    public static void devide() throws Exception {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入第一个数");
        int num1 = sc.nextInt();
        System.out.println("请输入第二个数");
        int num2 = sc.nextInt();
        if(num2 == 0){//除数为0,制造异常
            //制造运行时异常
            /*throw new RuntimeException();*/
            //制造检查时异常
            /*try {
                throw new Exception();
            } catch (Exception e) {
                e.printStackTrace();
            }*/
            throw new Exception();

        }else {
            System.out.println("商:"+num1/num2);

        }
    }
}

总结,throw和throws的区别:

(1)位置不同:

throw:方法内部

throws:方法的签名处,方法的声明处

(2)内容不同:

throw+异常对象(检查异常,运行时异常)

throws+异常的类型(可以多个类型,用逗号拼接)

(3)作用不同:

throw:异常出现的源头,制造异常。

throws:在方法的声明处,告诉方法的调用者,这个方法可能会出现我声明的这些异常。然后调用者对这个异常进行处理:要么自己处理,要么再继续向外抛出异常

异常练习:

package com.hhf.test02;

import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil;


public class Student {
    private String name;
    private int age;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) throws Exception {
        if (sex.equals("男")||sex.equals("女")){
            this.sex = sex;
        }else{//非男非女
            //解决办法1
           /* this.sex="男";*/
            //解决办法2:给个友好型提示,但是打印结果为默认的null效果
           /* System.out.println("对不起,你的性别输入错误了");*/
            //解决办法3——制造运行时异常
            /*throw new RuntimeException("性别不对");*/
            //解决方法4--制造检查时异常
           /* try {
                throw new Exception();
            } catch (Exception e) {
                e.printStackTrace();
            }*/
            //解决办法5--”甩锅法“
            throw new Exception();
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

    public Student() {
    }

    public Student(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        //this.sex = sex;
        try {
            this.setSex(sex);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.hhf.test02;


public class Test {
    public static void main(String[] args) {
        //创建一个student的对象
        Student s = new Student();
        s.setName("菲菲");
        s.setAge(19);
        try {
            s.setSex("kjashkd");
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(s);
    }

    Student s2 = new Student("娜娜", 21, "女");
}

ps:重载和重写的区别

 六、自定义异常

自定义异常可以继承运行时异常:

package com.hhf.test04;


public class MyException extends RuntimeException {
    static final long serialVersionUID = -703489719074L;
    public MyException(){

    }
    public MyException(String msg){
        super(msg);
    }
}

也可以继承检查异常:

package com.hhf.test04;


public class MyException extends Exception {
    static final long serialVersionUID = -703489719074L;
    public MyException(){

    }
    public MyException(String msg){
        super(msg);
    }
}

如果继承的是运行时异常,那么在使用的时候无需额外处理

如果继承的是检查异常,那么需要使用try-catch或者throws向上抛

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值