Java基础 第三节 第十九课

概述

Java 异常处理的五个关键字: try, catch, finally, throw, throws.

抛出异常

在编写程序时, 我们必须要考虑程序出现问题的情况. 比如, 在定义方法是=时, 方法需要接受参数. 那么, 当调用方法使用接受到参数时, 首先需要先对参数数据进行合法的判断. 若数据不合法, 就应该告诉调用者, 传递合法的数据进来. 这是需要使用抛出异常的方式来告诉调用者.

在 Java 中, 提供了一个 throw 关键字, 它用来抛出一个指定的异常对象. 那么, 抛出一个异常具体如何操作呢?

  1. 创建一个异常对象, 封装一些提示信息 (信息可以自己编写)
  2. 需要将这个异常对象告知给调用正则. 怎么告知呢? 怎么将这个异常对象传递到调用者处呢? 通过关键字 throw 就可以完成. throw 异常对象.

使用

throws 用在方法内, 用来抛出一个异常对象, 将这个异常对象传递到调用者处, 并结束当前方法的执行.

使用格式:

throw new 异常类名(参数);

例如:

throw new NullPointerException("要访问的arr数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");

学习完抛出异常的格式后, 我们通过下面程序演示下 throw 的使用. 代码如下:

public class Test {
    public static void main(String[] args) {
        // 创建一个数组
        int[] array = {1, 2, 3, 4, 5, 6};
        // 根据索引找到对应的元素
        int index = 6;
        int element = getElement(array, index);
    }

    /**
     * @param array 传入的int数组
     * @param index 需要查找的index
     * @return 返回指定索引的值
     */
    public static int getElement(int[] array, int index) {
        // 判断是否越界
        if (index < 0 || index > array.length - 1) {
            /*
            判断条件如果满足, 方执行完throw抛出异常对象后, 方法已经无法继续运算
            这是就会结束当前方法的执行, 并将异常告知给调用者. 这时就需要通过异常来解决
             */
            throw new ArrayIndexOutOfBoundsException("小哥哥, 索引越界了~~");
        }
        int element = array[index];
        return element;
    }
}

调试输出:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 小哥哥, 索引越界了~~
	at Test41.getElement(Test41.java:22)
	at Test41.main(Test41.java:7)

注意:

  • 如果产生了问题, 我们就会 throw 将问题描述类即异常进行抛出, 也就是将问题返回给该方法的调用者
  • 那么对于调用者来说, 该怎么处理呢?
    一种是进行捕获处理, 另一种就是继续讲问题声明出去, 使用 throws 声明处理出去, 使用 throws 声明处理

Objects 非空判断

还记得我们学习过一个类 Objects 吗, 曾经提到过它由一些静态的实用方法组成, 这些方法是 null-save (空指针安全的) 或 null-tolerant (容忍空指针的). 那么在它的源码中, 对对象为 null 的值进行了抛出异常操作.

public static <T> T requireNoNull(T obj): 查看指定引用对象不是 null.

查看源码发现这里对为 null 的进行了抛出异常操作:

 public static <T> T requireNonNull(T obj){
        if (obj == null){
            throw new NullPointerException();
        }
        return obj;
    }

声明异常 throws

声明异常: 将问题标识出来, 报告给调用者. 如果方法内通过 throw 抛出了编译时异常, 而没有捕获处理 (稍后讲解该方式). 那么必须通过 throws 进行声明, 让调用者去处理.

关键字 throws 运用于方法声明之上, 同于表示放弃方法不处理异常, 而是提醒该方法的调用者来处理异常. (抛出异常)

声明异常格式:

修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{   }

声明异常的代码演示:

import java.io.FileNotFoundException;

public class Test {
    public static void main(String[] args) throws FileNotFoundException {
        read("a.txt");
    }
    
    // 如果定义功能有时间发生需要报告给调用者. 可以通过在方法上面throws关键字进行声明
    public static void read(String path) throws FileNotFoundException {
        if(!path.equals("a.txt")){  // 如果不是a.txt 这个文件
            // 我假设如果a.txt认为该文件不存在是一个错误也就是异常throw
            throw new FileNotFoundException("文件不存在");
        }
    }
}

捕获异常 try…catch

如果异常出现的话, 会立刻终止程序, 所以我们得处理异常:

  1. 该方法不处理, 而是声明抛出, 有该方法调用者来处理 (throws)
  2. 在方法中使用 try-catch 的语句块来处理异常.

try-catch 的方式就是捕获异常: Java 中对异常有针对性的语句进行捕获, 可以对出现的异常进行制定方式的处理.

捕获异常语法如下:

try{
     编写可能会出现异常的代码
}catch(异常类型  e){
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}

try: 该代码块中编写可能产生异常的代码.
catch: 用来进行某种异常的捕获, 实现对捕获到的异常进行处理.

代码展示

import java.io.FileNotFoundException;

public class Test44 {
    public static void main(String[] args) {
        try {
            read("a.txt");
        } catch (FileNotFoundException e) {
            System.out.println(e);
        }
        System.out.println("over");
    }

    // 如果定义功能有时间发生需要报告给调用者. 可以通过在方法上面throws关键字进行声明
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("a.txt")) {  // 如果不是a.txt 这个文件
            // 我假设如果a.txt认为该文件不存在是一个错误也就是异常throw
            throw new FileNotFoundException("文件不存在");
        }
    }
}

注: try 和 catch 都不能单独使用, 必须连用.

获取异常信息

如何获取异常信息?

Throwable 类中定义了一些查看方法:

  • public String getMessage(): 获取异常的描述信息, 原因 (提示给用户的时候, 就提示错误原因)
  • public String toString(): 获取异常的类型和异常描述信息 (不用)
  • public void printStackTrace(): 打印异常的跟踪栈的信息并输出到控制台

注: 包含了异常的类型, 异常的原因, 还包括异常出现的wiz, 在开发和调试阶段, 都得使用printStackTrace

finally 代码块

finally: 有一些特定的代码无论异常是否发生, 都需要执行. 另外, 因为异常会引发程序跳转, 导致有些语句执行不到. 而 finally 就是解决这个问题的, 在 finally 代码块中存放的代码都是一定会被执行的.

什么时候的代码必须最终执行?

当我们在 try 语句块中打开了一些物理资源 (磁盘文件/网络连接/数据库连接等). 我们都得在使用完之后, 最终关闭打开的资源.

比如我们之后学习的 IO 流中, 当打开了一个关联的文件的资源, 最后程序不管结果如何, 都需要把这个资源关闭掉.

代码演示

import java.io.FileNotFoundException;

public class Test45 {
    public static void main(String[] args) {
        try {
            read("a.txt");
        } catch (FileNotFoundException e) {
            //抓取到的是编译期异常, 抛出去的是运行期
            throw new RuntimeException(e);
        } finally {
            System.out.println("不管程序怎样, 这里都将会被执行!");
        }
        System.out.println("over");
    }
    /*
     *
     * 我们当前的这个方法中有异常有编译期异常
     */
    public static void read(String path) throws FileNotFoundException {
        if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
            // 我假设 如果不是a.txt, 认为该文件不存在, 是一个错误也就是异常, throw
            throw new FileNotFoundException("文件不存在");
        }
    }
}

注: 当只有在 try 或者 catch 中调用退出 JVM 的相关方法, 此时 finally 才不会执行, 否则finally 永远会执行.

异常注意事项

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

  1. 多个异常分别处理
  2. 多个异常一次捕获, 多次处理
  3. 多个异常一次捕获一次处理

一般我们是使用一次捕获多次处理的方式, 格式如下:

try{
     编写可能会出现异常的代码
}catch(异常类型A  e){  当try中出现A类型异常,就用该catch来捕获.
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}catch(异常类型B  e){  当try中出现B类型异常,就用该catch来捕获.
     处理异常的代码
     //记录日志/打印异常信息/继续抛出异常
}

注: 这种异常处理方式, 要求多个 catch 中的异常不能相同, 并且若 catch 中的多个异常之间有子类和父类异常的关系, 那么子类异常要求在上面的 catch 处理, 鱼类异常在下面的 catch 处理.

总结

  • 运行时异常被抛出可以不处理, 即不捕获也不声明抛出
  • 如果 finally 有 return 语句, 永远返回 finally 中的结果, 避免该情况
  • 如果父类抛出了多个异常, 子类重写父类方法时, 抛出和父类相同的异常或者是父类的子类或者不抛出异常
  • 父类方法没有抛出异常, 子类重写父类方法时也不可抛出异常, 此时子类产生该异常, 只能捕获, 不能声明抛出
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值