Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 477|回复: 0

Java 异常的处理

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-7-22 21:01:00 | 显示全部楼层 |阅读模式

    throw关键字

    作用

    可以使用throw关键字在指定的方法中抛出指定的异常

    使用格式

    throw new xxxException(“异常产生的原因“)

    注意

    1. throw关键字必须写在方法的内部
    2. throw关键字后边new的对象必须是 Exception或者 Exception的子类对象
    3. throw关键字抛出指定的异常对象,我们就必须处理这个异常对象。
    4. throw关键字后边创建的是 RuntimeException或者是RuntimeException的子类对象,我们可以不处理,默认交给JW处理(打印异常对象,中断程序)
    5. throw关键字后边创建的是编译异常,我们就必须处理这个异常,要么 throws,要么try...catch

    举例

    例子1:

    public class DemoThrow {
        public static void main(String[] args) {
            int[] array = {};
    
            int element = DemoThrow.getElement(array, 1);
        }
    
        public static int getElement(int[] array, int index) {
            if (array.length == 0) {
                throw new NullPointerException("传入的数组为空");
            } else if (index == 0 || index > array.length - 1) {
                throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的适用范围");
            } else {
                return array[index];
            }
        }
    }
    抛出错误:
    Exception in thread "main" java.lang.NullPointerException: 传入的数组为空
        at XXX.DemoThrow.getElement(DemoThrow.java:10)
        at XXX.DemoThrow.main(DemoThrow.java:5)

     

    例子2:

    public class DemoThrow {
        public static void main(String[] args) {
            int[] array = {1, 2, 3};
    
            int element = DemoThrow.getElement(array, 100);
        }
    
        public static int getElement(int[] array, int index) {
            if (array.length == 0) {
                throw new NullPointerException("传入的数组为空");
            } else if (index == 0 || index > array.length - 1) {
                throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的适用范围");
            } else {
                return array[index];
            }
        }
    }
    抛出错误:
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 传递的索引超出了数组的适用范围
        at XXX.DemoThrow.getElement(DemoThrow.java:12)
        at XXX.DemoThrow.main(DemoThrow.java:5)

     

    Objects非空判断requireNonNull

    java.util.Objects类是由一些静态实用方法组成,这些方法是空指针安全的(即:容忍空指针的)

    在源码中对对象null值进行了抛出异常错误

    源码如下:
    // 查看指定对象时不时null
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }

    requireNonNull方法的使用

    import java.util.Objects;
    
    public class DemoObjectsNonNull {
        public static void main(String[] args) {
            String s = null;
            Objects.requireNonNull(s, "传入的参数为空");
        }
    }
    抛出错误:
    Exception in thread "main" java.lang.NullPointerException: 传入的参数为空
        at java.util.Objects.requireNonNull(Objects.java:228)
        at XXX.DemoObjectsNonNull.main(DemoObjectsNonNull.java:6)

     

    自定义非空判断

    public class DemoObjectsNonNull {
        public static void main(String[] args) {
            String s = null;
            methodNonNull(s);
        }
        
        public static <E> void methodNonNull(E e) {
            if (e == null) {
                throw new NullPointerException("传入的参数为空");
            }
        }
    }
    抛出错误:
    Exception in thread "main" java.lang.NullPointerException: 传入的参数为空
        at XXX.DemoObjectsNonNull.methodNonNull(DemoObjectsNonNull.java:9)
        at XXX.DemoObjectsNonNull.main(DemoObjectsNonNull.java:5)

     

    异常处理的第一种方式:throws

    throws作用

    当方法内部抛出异常对象的时候,那么我们就必须处理这个异常对象。可以使用 throws关键字处理异常对象,它会把异常对象声明抛给方法的调用者处理(自己不处理,绐别人处理)最终交给JVM-->中断处理

     

    使用格式

    修饰符 返回值类型 方法名(参数列表) throws AaaException, BbbException ... {
        throw new AaaException("产生原因");
        throw new BbbException("产生原因");
        ...
    }

     

    注意

    1. throws关键字必须写在方法声明处。
    2. throws关键字后边声明的异常必须是Exception或者是Exception的子类。
    3. 方法内部如果抛出了多个异常对象,那么throws后边必须也声明多个异常。如果批出的多个异常对象有子父类关系,那么直接声明父类异常即可
    4. 调用了一个声明抛出异常的方法,我们就必须处理声明的异常,要么继续使用throws声明抛出,交给方法的调用者处理,最终交给JVM,要么try...catch自己处理异常。

     

    举例

    例子1:

    import java.io.FileNotFoundException;
    
    public class Demo01Throws {
        public static void main(String[] args) throws FileNotFoundException{
            String s = "/Users/data.txt";
            readFile(s);
        }
    
        public static void readFile(String s) throws FileNotFoundException {
            if ("/Users/data.txt".equals(s)) {
                System.out.println("传入的参数是'/Users/data.txt'");
            } else {
                throw new FileNotFoundException("传入的参数不是'/Users/data.txt'");
            }
        }
    }
    输出结果:
    传入的参数是'/Users/data.txt'

     

    例子2:

    import java.io.FileNotFoundException;
    
    public class Demo01Throws {
        public static void main(String[] args) throws FileNotFoundException{
            String s = "/Users/data";
            readFile(s);
        }
    
        public static void readFile(String s) throws FileNotFoundException {
            if ("/Users/data.txt".equals(s)) {
                System.out.println("传入的参数是'/Users/data.txt'");
            } else {
                throw new FileNotFoundException("传入的参数不是'/Users/data.txt'");
            }
        }
    }
    抛出错误:
    Exception in thread "main" java.io.FileNotFoundException: 传入的参数不是'/Users/data.txt'
        at XXX.Demo01Throws.readFile(Demo01Throws.java:11)
        at XXX.Demo01Throws.main(Demo01Throws.java:6)

     

    异常处理的第二种方式:try catch

    使用格式

    格式:
    try {
        ...
    } catch (异常类名 变量名) {
        ...
    }
    ...
    catch(异常类名 变量名) {
        ...
    } ...

     

    注意

    1. try中可能会抛出多个异常对象,那么就可以使用多个catch来处理这些异常对象。
    2. 如果try中产生了异常,那么就会执行ctch中的异常处理逻辑,执行完catch中的处理逻辑,会继续执行try...catch之后的代码。
    3. 如果try中没有产生异常,那么就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try...catch之后的代码。

     

    举例

    public class Demo01TryCatch {
        public static void main(String[] args) {
    
            try {
                String[] strings = {};
                System.out.println(strings[100]);
            } catch (ArrayIndexOutOfBoundsException e) {
                // 数组索引越界异常
                System.out.println("Exception in thread \"main\" java.lang.ArrayIndexOutOfBoundsException");
            } catch (NullPointerException e) {
                // 空指针异常
                System.out.println("Exception in thread \"main\" java.lang.NullPointerException");
            }
            System.out.println("程序执行完成");
        }
    }
    输出结果:
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
    程序执行完成

     

    Throwable类中3个异常处理的方法

    public void printStackTrace():打印异常的跟踪栈信息,并输出到控制台。包含了异常的类型,异常的原因,还包括异常出现的位置。在开发和调试阶段都得使用printStackTrace。
    public String getMessage():获取发生异常的原因。提示给用户时候就提示误原因。
    public String toString():获取异常的类型和异常描述信息。

    printStackTrace()方法源码

    public void printStackTrace() {
            printStackTrace(System.err);
    }

     

    getMessage()方法源码

    public String getMessage() {
            return detailMessage;
    }

     

    toString()方法源码

    public String toString() {
            String s = getClass().getName();
            String message = getLocalizedMessage();
            return (message != null) ? (s + ": " + message) : s;
    }

     

    三个方法举例

    public class DemoTryCatch {
        public static void main(String[] args) {
            try {
                String[] strings = new String[10];
                getElement(strings, 10);
            } catch (ArrayIndexOutOfBoundsException e) {
                // 获取发生异常的原因
                System.out.println(e.getMessage());
                // 获取异常的类型和异常描述信息
                System.out.println(e.toString());
                // 获取栈的跟踪信息(异常的类型、异常的原因、异常出现的位置)
                e.printStackTrace();
            }
        }
    
        public static String getElement(String[] array, int index) {
            if (array.length == 0) {
                throw new NullPointerException("传入的数组为空");
            } else if (index == 0 || index > array.length - 1) {
                throw new ArrayIndexOutOfBoundsException("传递的索引超出了数组的适用范围");
            } else {
                return array[index];
            }
        }
    }
    控制台输出:
    传递的索引超出了数组的适用范围
    java.lang.ArrayIndexOutOfBoundsException: 传递的索引超出了数组的适用范围
    java.lang.ArrayIndexOutOfBoundsException: 传递的索引超出了数组的适用范围 at XXX.DemoTryCatch.getElement(DemoTryCatch.java:19)
        at XXX.DemoTryCatch.main(DemoTryCatch.java:5)

     

    finally代码块

    格式

    try {
        ...
    } catch (异常类名 变量名) {
        ...
    }
    ...
    catch(异常类名 变量名) {
        ...
    } finally {
        ...
    }

     

    注意

    1. finally不能单独使用,必须要和try一起使用

    2. finally一般用于资源释放(资源回收),无论程序是否出现异常,最后都要释放IO

     

    举例

    public class DemoFinally {
        public static void main(String[] args) {
    
            try {
                String[] strings = {};
                System.out.println(strings[100]);
            } catch (ArrayIndexOutOfBoundsException e) {
                // 获取异常的类型和异常描述信息
                System.out.println(e.toString());
            } finally {
                System.out.println("程序执行完成");
            }
    
        }
    }
    控制台输出:
    java.lang.ArrayIndexOutOfBoundsException: 100
    程序执行完成

     

    异常注意事项:多异常的捕获处理

    多个异常分别处理

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class Demo01ManyException {
        public static void main(String[] args) {
    
            try {
                int[] array = {1, 2, 3};
                int a = array[3];
            }
            catch (ArrayIndexOutOfBoundsException e) {
                System.out.println(e.toString());
            }
    
    
            try {
                List<Integer> list = new ArrayList<>();
                Collections.addAll(list, 1, 2, 3);
                int b = list.get(3);
            }
            catch (IndexOutOfBoundsException e) {
                System.out.println(e.toString());
            }
        }
    }
    控制台输出:
    java.lang.ArrayIndexOutOfBoundsException: 3
    java.lang.IndexOutOfBoundsException: Index: 3, Size: 3

     

    多个异常一次捕获多次处理

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class Demo01ManyException {
        public static void main(String[] args) {
    
            try {
                int[] array = {1, 2, 3};
                int a = array[3];
    
                List<Integer> list = new ArrayList<>();
                Collections.addAll(list, 1, 2, 3);
                int b = list.get(3);
            }
            catch (ArrayIndexOutOfBoundsException e) {
                System.out.println(e.toString());
            }
            catch (IndexOutOfBoundsException e) {
                System.out.println(e.toString());
            }
            
        }
    }
    控制台输出:
    java.lang.ArrayIndexOutOfBoundsException: 3

    注意:一个try,多个catch,catch里面定义的异常变量,如果有子父类关系,那么子类的异常变量必须写在前面,否则会报错

    ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException

     

     

     

    多个异常一次捕获一次处理

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class Demo01ManyException {
        public static void main(String[] args) {
    
            try {
                int[] array = {1, 2, 3};
                int a = array[3];
    
                List<Integer> list = new ArrayList<>();
                Collections.addAll(list, 1, 2, 3);
                int b = list.get(3);
            }
            catch (Exception e) {
                System.out.println(e.toString());
            }
    
        }
    }
    控制台输出:
    java.lang.ArrayIndexOutOfBoundsException: 3

     

    异常注意事项:finally有return语句

    如果finally中有return语句,只会返回finally中的值。

    如:

    public class Demo01FinallyReturn {
        public static void main(String[] args) {
            System.out.println(Demo01FinallyReturn.method());
        }
    
        public static String method() {
            try {
                String s = "abc";
                return s;
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                String s = "ABC";
                return s;
            }
        }
    }
    控制台输出:
    ABC

     

    子父类异常

    如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
    父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出。

    如:

    public class Fu {
    
        public static void method1() throws NullPointerException, ClassCastException { }
    
        public static void method2() throws IndexOutOfBoundsException { }
    
        public static void method3() { }
    
        public static void method4() { }
    
    }
    public class Zi extends Fu {
    
        /**
         * 子类重写父类方法时,抛出和父类相同的异常
         * @throws NullPointerException 空指针异常
         * @throws ClassCastException 类强制转换异常
         */
        public static void method1() throws NullPointerException, ClassCastException { }
    
        /**
         * 子类重写父类方法时,抛出父类异常的子类
         * @throws ArrayIndexOutOfBoundsException 索引越界异常
         */
        public static void method2() throws ArrayIndexOutOfBoundsException { }
    
        /**
         * 子类重写父类方法时,不抛出异常
         */
        public static void method3() { }
    
        /**
         * 父类方法没有抛出异常,子类重写父类方法时,也不可以抛出异常
         * 只能捕获处理,不能声明抛出
         */
        public static void method4(){
            try {
                throw new Exception("编译期异常");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }

     

    自定义异常类的简单练习

    要求

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

     

    分析

    1.使用数组保存已经注册过的用户名
    2.使用Scanner获取用户输入的注册的用户名
    3.定义一个方法,对用户输入中的注册用户名进行判断,遍历存储已经注册过用户名的数组,获取每一个用户名,
    使用获取到的用户名和用户输入的用户名比较
    true:用户名已经存在,抛出 RuntimeException异常,告知用户"亲,该用户名已经被注册" false:继续遍历比较。如果循环结束了,还没有找到重复的用户名,提示用户“恭喜您注册成功!"。

     

    实现

    import java.util.Scanner;
    
    public class MyUsersException {
    
        private static String[] names = {"小红", "小明", "李华", "小军", "大雄"};
    
        public static void registerUser(String scannerUser) {
            for (String name : names) {
                if (name.equals(scannerUser)) {
                    try {
                        throw new RuntimeException("亲,该用户名已被注册!");
                    } catch (RuntimeException e) {
                        System.out.println(e.getMessage());
                        return;
                    }
                }
            }
            System.out.println("恭喜您注册成功!");
        }
    
        public static void main(String[] args) throws RuntimeException{
            Scanner scn = new Scanner(System.in);
            System.out.print("输入要注册的用户名:");
            String registerUserName = scn.next();
            MyUsersException.registerUser(registerUserName);
        }
    }
    控制台输入:李华
    控制台输出:
    亲,该用户名已被注册!
    控制台输入:静香
    控制台输出:
    恭喜您注册成功!

     

      

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 09:35 , Processed in 0.069847 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表