Java语言学习day 13 - 异常

1 异常

1.1 异常的概念

  • 异常概念: 异常是程序在运行时出现的不正常情况.

    异常产生后没有正确的处理, 出导致程序的中断 , 造成损失, 开发中我们要考虑到各种可能发生的异常, 对其作出正确的处理, 保证程序正常执行.

1.2 异常的继承体系

在这里插入图片描述

  • Throwable类: 包含2个子类Error( 错误 )和Exception( 异常 ).

1.3 Error

  • Error: 代码运行时在JVM出现问题. 我们需要修改代码来解决该错误.

常见的Error:

  • StackOverflowError: 当应用程序递归太深而发生堆栈溢出时, 抛出该错误. 比如死循环或者没有出口的递归调用.

  • OutOfMemoryError: 因为内存溢出或没有可用的内存提供给垃圾回收器时, Java 虚拟机无法分配一个对象, 这时抛出该错误. 比如new了非常庞大数量的对象而没释放.

1.4 Exception

  • Exception: 表示程序运行时出现的不正常的情况, 一般大多数都是表示轻度到中度的问题, 属于可预测, 可恢复的问题. 我们需要通过合理的异常处理, 让程序正常的运行直到程序完成.

常见的Exception:

  • ArrayIndexOutOfBoundsException: 用非法索引访问数组时抛出的异常. 如果索引为负或大于等于数组大小, 则该索引为非法索引. int[] arr = new int[ 10 ]; arr[10];就异常
  • ArithmeticException: 当出现异常的运算条件时,抛出此异常. 例如: 一个整数“除以零”时, 抛出此类的一个实例.
  • NullPointerException: 当应用程序试图在需要对象的地方使用 null 时, 抛出该异常. 这种情况包括:
  1. 调用 null 对象的实例方法.
  2. 访问或修改 null 对象的字段.
  3. 将 null 作为一个数组, 获得其长度等.
  • NumberFormatException: 数字格式化异常.比如: Integer.parseInt(“123aa”);

2 捕获异常

  • 异常一旦出现, 程序会立即终止, 在开发中我们一定要处理异常, 处理异常的两种方法:
  1. 直接处理异常( 捕获异常 ).
  2. 自身抛出异常, 不处理.

2.1 单个异常的捕获

处理异常的语法格式:

try{
    //可能会有异常的代码
}catch(要捕获的异常类型 变量){
    //处理异常的代码
}
public class TryCatchDemo {
    public static void main(String[] args) {
        System.out.println("开始");
        //divide方法虽然出错,但是已经异常处理,不会影响到调用方法继续向下执行
        divide(2, 0);
        //能够执行到结束
        System.out.println("结束");
    }

    public static void divide(int a, int b) {
        try {
            //可能会出现异常的代码
            System.out.println(a / b);
            //捕获到ArithmeticException异常
        } catch (ArithmeticException e) {
            //输出异常
            System.out.println("除法运算有错误");
        }
    }
}

当然也可以使用Exception和Throwable接受所有的异常对象( 多态 ).但是不建议使用Throwable,因为Throwable有Error和Exception, Error是没有必要处理的.

2.2 访问异常信息

  • String getMessage(): 返回异常信息.
  • void printStackTrace( ): 打印异常类型名和异常信息, 在程序中异常的位置.
public class TryCatchDemo {
    public static void main(String[] args) {
        System.out.println("开始");
        //divide方法虽然出错,但是已经异常处理,不会影响到调用方法继续向下执行
        divide(2, 0);
        //能够执行到结束
        System.out.println("结束");
    }

    public static void divide(int a, int b) {
        /* try {
            可能会出现异常的代码
        }catch (可能出现异常的类型 变量){
            //处理异常
            //获取到异常对象中封装的异常信息
        }*/
        try {
            //可能会出现异常的代码
            System.out.println(a / b);
            //捕获到ArithmeticException异常
        } catch (ArithmeticException e) {
            //输出异常
            System.out.println("除法运算有错误");
            //异常的信息
            System.out.println(e.getMessage());
            //打印异常类型名和异常信息, 在程序中异常的位置.
            e.printStackTrace();
        }
    }
}

2.3 捕获多个异常

  • 多个异常: 程序中存在多种异常.

捕获多个异常语法:

try{
    //可能会有异常的代码
}catch(要捕获的异常类型A 变量){
    //处理异常的代码
}catch(要捕获的异常类型B 变量){
    //处理异常的代码
...
}catch(要捕获的异常类型N 变量){
    //处理异常的代码
}
public class TryCatchCatchDemo {
    public static void main(String[] args) {
        divide("5", "a");
    }

    public static void divide(String a, String b) {
        try {
            //下面代码可能会出现两种异常
            //ArithmeticException
            //NumberFormatException
            int x = Integer.parseInt(a);
            int y = Integer.parseInt(b);
            System.out.println(x / y);
            //处理数字格式化异常
        } catch (NumberFormatException e) {
            System.out.println("数字格式化异常");
            e.printStackTrace();
            //处理算术异常
        } catch (ArithmeticException e) {
            System.out.println("算术异常");
            e.printStackTrace();
            //处理其他异常
            //父类异常不能放在第一个, 不然子类异常不管怎么样都访问不到了
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.4 finally

  • finally语法格式:
try{
	//可能会有异常的代码
}catch(要捕获的异常类型 变量){
	//处理异常的代码
}finally{
	//前面无论有没有异常,这里都执行
}

try语句块必须和catch语句块或try和finally同在, 不能单独存在try或catch或finally.

finally块总会执行, 不论是否有错误出现. 但如果try语句块中或catch语句块存在JVM退出代码( System.exit(0); ) , finally块就不会被执行了. 一般, 我们把关闭资源的代码放在finally里面, 保证资源总是能关闭.

public class TryCatchFinallyDemo {
    public static void main(String[] args) {
        divide("5", "0");
        System.out.println("结束");
    }

    public static void divide(String a, String b) {
        try {
            //下面代码可能会出现两种异常
            //ArithmeticException
            //NumberFormatException
            int x = Integer.parseInt(a);
            int y = Integer.parseInt(b);
            System.out.println(x / y);
            //处理数字格式化异常
        } catch (NumberFormatException e) {
            System.out.println("数字格式化异常");
            //System.exit(0);
            e.printStackTrace();
            //处理算术异常
        } catch (ArithmeticException e) {
            System.out.println("算术异常");
            e.printStackTrace();
            //System.exit(0);
            //try和catch中没有关闭资源代码(System.exit(0);)
            //finally中的语句无论怎么样都要执行
        } finally {
            System.out.println("finally");
        }
    }
}

3 抛出异常

  • 抛出异常: 自身抛出异常, 不处理, 而抛出异常, 有两种:

    1. 方法里面会出现异常, 但方法不想处理这个异常, 使用throw抛出异常对象.

    2. 方法里面可能会产生异常, 自身不想处理, 提醒调用该方法的方法做需要处理, 使用throws关键字.

3.1 throws关键字

  • throws: 在可能出现异常的方法上声明提醒可能会出现异常的类型.

throw语法格式:

修饰符 返回值类型 方法名(参数列表...) throws 异常A, 异常B..{
}
public class ThrowsDemo {
    public static void main(String[] args) {
        //如果调用的方法可能存在异常, 那我们应该选择处理或者抛出
        try {
            divide(3, 1);
            divide(3, 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //在方法声明上告知调用者, 这里可能存在Exception异常
    public static void divide(int a, int b)throws Exception {
        System.out.println(a / b);
    }
}

3.2 throw关键字

  • throw: 当方法内, 需要返回一个错误结果给调用者时, 一般使用throw关键字在方法内手动抛出一个具体的异常对象.
public class ThrowDemo {
    public static void main(String[] args) {
        try {
            isExist("");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }

    //检查用户名是否存在
    public static void isExist(String name) throws Exception {
        //通过一个数组模拟现在已经存在的用户名
        String[] n = {"LL", "ll"};
        if (name != null && name.length() > 0) {
            for (String n1 : n) {
                if (name.equals(n1)) {
                    //用抛异常的方式,告知调用者,这里存在问题
                    throw new Exception("对不起,用户名" + name + "已经存在");
                } else {
                    System.out.println("注册成功");
                }
            }
        }
        throw new Exception("用户名为空");
    }
}

3.3 throws和throw的区别

​ throws: 用于方法声明上, 表示该方法不需要处理某种类型异常,也在提醒该方法调用者需要处理异常.

​ throw: 用于返回一个错误结果, 抛出具体异常类的对象给调用者.

4 异常分类

  • 异常分类: 编译异常和运行异常.
  • RuntimeException和其子类属于运行异常, 其他都是编译异常.

4.1 运行异常

  • 运行异常: 在编译时期不被检测, 只有在运行时期才会被检查出来.

可以不使用try-catch和throws处理运行异常.

4.2 编译异常

  • 编译异常: 又称检查异常, 在编译时期就会被检测到的异常. 必须处理编译异常, 使用try-catch或throws处理.

4.3 自定义异常类

  • 自定义异常类: 一个异常类只表示某种特定的异常类型.
  • 自定义异常的两种方式: 可以继承Exception类或RuntimeException类. 一般推荐继承RuntimeException类.
  • 继承异常后: 我们需要提供无参构造和一个String类型参数构造器.

5 总结

5.1 什么是异常? 程序员为什么需要处理异常?

异常: 程序运行时出现的不正常情况.

为什么需要处理异常: 如果异常没有正确的处理, 或导致程序的中断.

5.2 Java的异常继承体系是什么?

Throwable->Error,Exception.

Exception->Exception, RuntimeException.

5.3 说说Throwable、Error、Exception的区别

Throwable: Error和Exception的父类,用来存储异常信息.

Error: 表示代码运行时JVM出现的错误, 一般用该代码来解决该问题.

Exception: 表示程序运行时的异常, 也就是一些不正常的情况, 需要我们通过合理的异常处理, 让程序正常.

5.4 说说异常的分类和区别

异常的分类: 捕获异常和抛出异常.

区别: 捕获异常是直接处理异常, 抛出异常是自身抛出异常不进行处理.

5.5 捕获异常是什么意思? 语法是什么?

捕获异常: 直接处理异常.

语法: try{

​ //可能出现异常的代码

​ }catch(要捕捉的异常类型 变量){

​ //处理捕获到的异常的代码

​ }

5.6 finally语句块的特点是什么?

try{

​ //可能出现异常的代码

​ }catch(要捕捉的异常类型 变量){

​ //处理捕获到的异常的代码

​ }finally{

​ //无论是不是有异常,最后都会执行代码

​ }

5.7 什么时候需要抛出异常? 语法是什么?

方法里面会出现异常, 但方法不想处理异常, 提醒调用该方法的人需要处理.

修饰符 返回值类型 方法名(参数列表…) throws 异常A, 异常B…{
}

5.8 说说throw和throws的区别

throw: 用于返回一个错误结果, 抛出具体异常类的对象给调用者.

throws: 用于方法声明的时候, 不想处理异常然后抛出异常, 提醒调用者需要处理异常.

5.9 自定义异常时需要注意哪些问题?
  1. 自定义异常可以继承Exception类和RuntimeException类. 一般推荐继承RuntimException.
  2. 继承以后, 一般需要提供一个无参构造器和一个带String类型参数的构造器.
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值