异常的注意事项、自定义异常类

一、多个异常使用捕获又该如何处理呢?

捕获:try
处理:catch
声明抛出:throws

  1. 多个异常分别处理。(控制台能输出多条处理信息)

  2. 多个异常一次捕获(try),多次处理(catch)。(控制台只会打印出现代码最前面的异常信息,第二个出现的异常打印不出来,得注释第一条异常才会输出第二条
    (catch里边定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在上边,否则就会报错,因为多态(还可以省略子类的catch只写父类的catch,所以一般写Exception这个大父类),因为父类 对象=new 子类对象已经可以了,再多一个catch就多余,所以报错了)

  3. 多个异常一次捕获一次处理(跟第二差不多,把catch改为一个大父类就行)。(控制台的情况跟第二一样)

代码:

import java.util.List;
/*
    异常的注意事项
 */
public class Demo01Exception {
    public static void main(String[] args) {
        //1. 多个异常分别处理。
       /* try {
            int[] arr = {1,2,3};
            System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
        }

        try{
            List<Integer> list = List.of(1, 2, 3);
            System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
        }catch (IndexOutOfBoundsException e){
            System.out.println(e);
        }*/

        //2. 多个异常一次捕获,多次处理。
        /*try {
            int[] arr = {1,2,3};
            //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
            List<Integer> list = List.of(1, 2, 3);
            System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
        }catch (IndexOutOfBoundsException e){
            System.out.println(e);
        }*/

        /*
            一个try多个catch注意事项:
                catch里边定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在上边,否则就会报错
                ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException
         */
        /*try {
            int[] arr = {1,2,3};
            //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
            List<Integer> list = List.of(1, 2, 3);
            System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
        }catch (IndexOutOfBoundsException e){
            System.out.println(e);
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println(e);
        }*/

        //3. 多个异常一次捕获一次处理。
        /*try {
            int[] arr = {1,2,3};
            //System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
            List<Integer> list = List.of(1, 2, 3);
            System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3
        }catch (Exception e){
            System.out.println(e);
        }*/

        //运行时异常被抛出可以不处理。即不捕获也不声明抛出。
        //默认给虚拟机处理,终止程序,什么时候不抛出运行时异常了,在来继续执行程序
        int[] arr = {1,2,3};
        System.out.println(arr[3]);//ArrayIndexOutOfBoundsException: 3
        List<Integer> list = List.of(1, 2, 3);
        System.out.println(list.get(3));//IndexOutOfBoundsException: Index 3 out-of-bounds for length 3

        System.out.println("后续代码!");
    }
}

二.如果finally有return语句,永远返回finally中的结果,避免该情况.(了解即可)

/*
    如果finally有return语句,永远返回finally中的结果,避免该情况.
 */
public class Demo02Exception {
    public static void main(String[] args) {
        int a = getA();
        System.out.println(a);
    }

    //定义一个方法,返回变量a的值
    public static int getA(){
        int a = 10;
        try{
            return a;
        }catch (Exception e){
            System.out.println(e);
        }finally {
            //一定会执行的代码
            a = 100;
            return a;
        }
    }
}

程序返回100而不是10

三、子父类异常

子父类的异常:

  • 如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
  • 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出(throws),但可以捕获处理(try-catch)
  • 注意(总的来说):
    父类异常时什么样,子类异常就什么样
public class Fu {
    public void show01() throws NullPointerException,ClassCastException{}
    public void show02() throws IndexOutOfBoundsException{}
    public void show03() throws IndexOutOfBoundsException{}
    public void show04() throws Exception {}
}

class Zi extends Fu{
    //子类重写父类方法时,抛出和父类相同的异常
    public void show01() throws NullPointerException,ClassCastException{}
    //子类重写父类方法时,抛出父类异常的子类
    public void show02() throws ArrayIndexOutOfBoundsException{}
    //子类重写父类方法时,不抛出异常
    public void show03() {}

    /*
        父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。

     */
    //public void show04() throws Exception{}

    //此时子类产生该异常,只能捕获处理,不能声明抛出
    public void show04()  {
        try {
            throw  new Exception("编译期异常");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

四、自定义异常类

自定义异常类:
java提供的异常类,不够我们使用,需要自己定义一些异常类
格式:
public class XXXExcepiton extends Exception | RuntimeException{
添加一个空参数的构造方法
添加一个带异常信息的构造方法
}
注意:
1.自定义异常类一般都是以Exception结尾,说明该类是一个异常类
2.自定义异常类,必须的继承Exception或者RuntimeException
若果继承Exception:那么自定义的异常类就是一个编译期异常,如果方法内部抛出了编译期异常,就必须处理这个异常,要么throws,要么try…catch
如果继承RuntimeException:那么自定义的异常类就是一个运行期异常,无需处理,交给虚拟机处理(中断处理)

  • 继承Exception,则要hrows,要么try…catch:
import java.util.Scanner;

class RegisterException extends Exception{
    //添加一个空参数的构造方法(记住要super就行)
    public RegisterException(){
        super();
    }
    /*
        添加一个带异常信息的构造方法
        查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息
     */
    public RegisterException(String message){
        super(message);
    }
}

/*
    要求:我们模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。

    分析:
        1.使用数组保存已经注册过的用户名(数据库)
        2.使用Scanner获取用户输入的注册的用户名(前端,页面)
        3.定义一个方法,对用户输入的中注册的用户名进行判断
            遍历存储已经注册过用户名的数组,获取每一个用户名
            使用获取到的用户名和用户输入的用户名比较
                true:
                    用户名已经存在,抛出RegisterException异常,告知用户"亲,该用户名已经被注册";
                false:
                    继续遍历比较
            如果循环结束了,还没有找到重复的用户名,提示用户"恭喜您,注册成功!";
 */
public class DemoRegisterException {
    // 1.使用数组保存已经注册过的用户名(数据库)
    static String[] usernames={"张三","李四","王五"};
    public static void main(String[] args) /*throws RegisterException*/ {
        //2.使用Scanner获取用户输入的注册的用户名(前端,页面)
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入您要注册的用户名:");
        String username = sc.next();
        checkUsername(username);

    }

    //3.定义一个方法,对用户输入的中注册的用户名进行判断
    private static void checkUsername(String username) /*throws RegisterException*/ {
        //遍历存储已经注册过用户名的数组,获取每一个用户名
        for (String name : usernames) {
            //使用获取到的用户名和用户输入的用户名比较
            if (name.equals(username)){
                //true:用户名已经存在,抛出RegisterException异常,告知用户"亲,该用户名已经被注册";
                try {
                    throw new RegisterException("亲,该用户已经被注册!");
                } catch (RegisterException e) {
                    e.printStackTrace();
                    return;
                }finally {
                    System.out.println("如果有return,finally还是会被输出的!!!");
                }
            }
        }

        //如果循环结束了,还没有找到重复的用户名,提示用户"恭喜您,注册成功!";
        System.out.println("恭喜您,注册成功!");//有return就不输出了
    }
}

  • 继承RuntimeException,可不处理(如果你想处理(用throws或者try-catch),也不会报错哦),默认虚拟机处理:
import java.util.Scanner;

class RegisterException extends RuntimeException{
    //添加一个空参数的构造方法(记住要super就行)
    public RegisterException(){
        super();
    }
    /*
        添加一个带异常信息的构造方法
        查看源码发现,所有的异常类都会有一个带异常信息的构造方法,方法内部会调用父类带异常信息的构造方法,让父类来处理这个异常信息
     */
    public RegisterException(String message){
        super(message);
    }
}

/*
    要求:我们模拟注册操作,如果用户名已存在,则抛出异常并提示:亲,该用户名已经被注册。

    分析:
        1.使用数组保存已经注册过的用户名(数据库)
        2.使用Scanner获取用户输入的注册的用户名(前端,页面)
        3.定义一个方法,对用户输入的中注册的用户名进行判断
            遍历存储已经注册过用户名的数组,获取每一个用户名
            使用获取到的用户名和用户输入的用户名比较
                true:
                    用户名已经存在,抛出RegisterException异常,告知用户"亲,该用户名已经被注册";
                false:
                    继续遍历比较
            如果循环结束了,还没有找到重复的用户名,提示用户"恭喜您,注册成功!";
 */
public class DemoRegisterException {
    // 1.使用数组保存已经注册过的用户名(数据库)
    static String[] usernames={"张三","李四","王五"};
    public static void main(String[] args) {
        //2.使用Scanner获取用户输入的注册的用户名(前端,页面)
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入您要注册的用户名:");
        String username = sc.next();
        checkUsername(username);

    }

    //3.定义一个方法,对用户输入的中注册的用户名进行判断
    private static void checkUsername(String username){
        //遍历存储已经注册过用户名的数组,获取每一个用户名
        for (String name : usernames) {
            //使用获取到的用户名和用户输入的用户名比较
            if (name.equals(username)){
                //true:用户名已经存在,抛出RegisterException异常,告知用户"亲,该用户名已经被注册";
                throw new RegisterException("亲,该用户已经被注册!");//抛出运行期异常,无需处理,交给JVM处理,中断处理
            }
        }
        //如果循环结束了,还没有找到重复的用户名,提示用户"恭喜您,注册成功!";
        System.out.println("恭喜您,注册成功!");//有return就不输出了
    }
}

上面两个代码,关键是for遍历后,输出 System.out.println(“恭喜您,注册成功!”);放的位置,以及程序遇到异常,它还会不会输出?
用throws遇到异常就不会输出,或者是运行时异常,jvm默认也不输出)或者不想输出也可以用try-catch(在catch里面return就行),如果想遇到异常还输出它的话,可以用没有return 的try-catch。

finally会覆盖try或者catch里面的return:

package com.yuan.demo9;

/**
 * @author QLBF
 * @version 1.0
 * @date 2021/6/12 9:47
 */
public class Demo {
    public static void main(String[] args){
        System.out.print(getNumber(0));
        System.out.print(getNumber(1));
        System.out.print(getNumber(2));
        System.out.print(getNumber(4));
    }

    public static int getNumber(int num){
        try{
            int result = 2 / num;
            return result;
        }catch (Exception exception){
            return 0;
        }finally{
            if(num == 0){
                return -1;
            }
            if(num == 1){
                return 1;
            }
        }

    }
}

输出:-1110

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值