学习Java之异常到底该如何捕获和处理

 更新时间:2023年08月10日 08:23:37   作者:一一哥Sun  
我们知道,Java的异常处理是通过5个关键字来实现的,即try、catch、throw、throws和finally,try catch语句用于捕获并处理异常,但具体该怎么捕获异常,怎么抛出异常,什么时候抛,什么时候捕,感兴趣的小伙伴跟着小编一起来看看吧

一. 捕获和处理异常

1. 概述

在Java中,如果某行或某几行代码有可能会抛出异常,我们此时就可以用try ... catch ... finally进行捕获处理。把可能发生异常的语句放在try { ... }语句中,然后使用catch语句捕获对应的Exception及其子类,把必须执行的代码放在finally语句中。接下来我们就来看看具体的代码实现吧。

2. try-catch结构

2.1 基本语法

首先我们来看看try-catch的基本语法:

try {
    // 可能发生异常的语句
} catch(Exception e) {
    // 处理异常语句
}

在上面的语法中,我们要把可能引发异常的语句封装在try语句块中,用于捕获可能发生的异常。catch语句里的( )中,要传入与try语句里匹配的异常类,指明catch语句可以处理的异常类型。

也就是说,如果此时try语句块中发生了某个异常,那么这个相应的异常对象就会被拋出,产生异常的这行代码之后的其余代码就不会再被执行。然后catch语句就开始执行,把try中拋出的异常对象进行捕获并处理。
当然,如果try语句块中没有发生异常,那么try里的代码就会正常执行结束,而后面的catch就会被跳过。

这里我们需要注意:try...catch与if...else是不一样的,try后面的花括号{ }不可以省略,即便try中只有一行代码。同样的,catch的花括号 { } 也不可以省略。另外,try语句块中声明的变量属于局部变量,它只在try中有效,其它地方不能访问该变量。

2.2 代码实现

接下来设计一个代码案例,来讲解try-catch的用法:

/**
 * @author
 */
public class Demo01 {
    public static void main(String[] args) {
        //定义一个长度为3的数组
        int[] array = new int[3];
        try {
            //索引超出了数组长度,将会引发ArrayIndexOutOfBoundsException数组下标越界异常
            array[3] = 1; 
            //发生异常后,这行代码并不会执行
            System.out.println("数组:" + array.toString());
        } catch (ArrayIndexOutOfBoundsException e) {
            //指出异常的类型、性质、栈层次及出现在程序中的位置
            e.printStackTrace();
            //输出错误的原因及性质
            System.out.println("数组越界:" + e.getMessage());
            //输出异常的类型与性质
            System.out.println("数组越界:" + e.toString());
        }
    }
}

在上面这段代码中,小编在try语句中创建了一个长度为3的整数数组,并尝试着将第4个位置上的元素值设为1。由于数组越界,这会引发代码故障,java会抛出一个ArrayIndexOutOfBoundsException异常。由于发生了异常,所以后面的数组输出语句就不会被执行。

而我们在catch中接收了ArrayIndexOutOfBoundsException异常,这个异常与try中抛出的异常是一致的,所以代码会跳转到catch中进行异常的处理。另外在上面的处理代码块中,我们可以通过Exception异常对象的以下方法,来获取到相应的异常信息。

  • printStackTrace()方法:输出异常栈信息,指出异常的类型、性质、栈层次及出现在程序中的位置;
  • getMessage()方法:输出错误的性质;
  • toString()方法:输出异常的类型与性质。

3. 多重catch结构

我们在编写java代码时,多行语句有可能会产生多个不同的异常,你们面对这个多个异常该怎么处理呢?其实我们可以使用多重catch语句来分别处理多个异常。

3.1 基本语法

多重catch语句的基本语法格式如下:

try {
    // 可能会发生异常的语句
} catch(ExceptionType e) {
    // 处理异常语句
} catch(ExceptionType e) {
    // 处理异常语句
} catch(ExceptionType e) {
    // 处理异常语句
	...
}

当存在多个catch代码块时,只要有一个catch代码块捕获到一个异常,其它的catch代码块就不再进行匹配。但是我们要注意,当捕获的多个异常类之间存在父子关系时,一般是先捕获子类,再捕获父类。所以我们在编写代码时,要把子类异常放在父类异常的前面,否则子类就会捕获不到。

3.2 代码实现

接下来给大家设计了一个利用IO流读取文件内容的案例,这段代码就可能会出现两个异常。

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
 * @author 一一哥Sun
 */
public class Demo02 {
    //多重catch语句
    public static void main(String[] args) {
        //定义一个缓冲流对象,以后在IO流阶段壹哥会细讲
        BufferedReader reader = null;
        try {
            //对接一个file.txt文件,该文件可能不存在
            reader = new BufferedReader(new FileReader("file.txt"));
            //读取文件中的内容。所有的IO流都可能会产生IO流异常
            String line = reader.readLine();
            while (line != null) {
                System.out.println(line);
                line = reader.readLine();
            }
        } catch (FileNotFoundException e) {
        	//处理文件不存在时的异常
            System.out.println("文件不存在:" + e.getMessage());
        } catch (IOException e) {
        	//处理IO异常
            System.out.println("读取文件失败:" + e.getMessage());
        } 
	}
}

在这段代码中,我们尝试打开一个名为file.txt的文件,并逐行读取其内容。如果该文件不存在或读取失败,程序将会在相应的catch块中处理异常,并打印出异常消息。具体地来说,就是try代码块的第16行代码调用了FileReader的构造方法,这里有可能会发生FileNotFoundException异常。而第18行调用BufferedReader输入流的readLine()方法时,有可能会发生IOException异常。

因为FileNotFoundException异常是IOException异常的子类,所以我们应该先捕获 FileNotFoundException异常,即第23行代码;后捕获IOException异常,即第26行代码。但是如果我们将FileNotFoundException和IOException异常的捕获顺序进行调换,那么捕获FileNotFoundException异常的代码块永远也不会执行,所以FileNotFoundException异常也永远不会被处理。当然,如果多个异常之间没有父子关系,则其顺序就无所谓了。

4. try-catch-finally结构

在上面的代码中,我们涉及到了IO流的相关内容,这一块我们还没有开始进行学习,会在以后给大家进行详细地讲解。

IO流属于一种比较消耗物理资源的API,使用完之后应该把IO流进行关闭,否则就可能会导致物理资源被过多的消耗。那么我们该在哪里关闭IO流呢?有的人会说,我们可以在try语句块执行完正常的功能后关闭IO流。但是大家要知道,try语句块和catch语句块有可能因为异常并没有被完全执行,那么try里打开的这些物理资源到底要在哪里回收呢?

为了确保这些物理资源一定可以被回收,异常处理机制给我们提供了finally代码块,且Java 7之后又提供了自动资源管理(Automatic Resource Management)技术,更是可以优雅地解决资源回收的问题。

4.1 基本语法

无论是否发生异常,finally里的代码总会被执行。在 finally代码块中,我们可以执行一些清理等收尾善后性质的代码,其基本语法格式如下:

try {
    // 可能会发生异常的语句
} catch(ExceptionType e) {
    // 处理异常语句
} finally {
    // 执行清理代码块,这里的代码肯定会被执行到,除非极特殊的情况发生
}

上面的代码中,无论是否发生了异常(除极特殊的情况外,比如提前调用了System.exit()退出虚拟机的方法),finally语句块中的代码都会被执行。另外,finally语句也可以直接和try语句配合使用,其语法格式如下:

try {
    // 逻辑代码块
} finally {
    // 清理代码块
}

我们在使用try-catch-finally语句时要注意以下几点:

在异常处理的语法结构中,只有try是必需的。如果没有try代码块,则不能有后面的catch和finally;

虽然catch块和finally块是可选的,但也不能只有try块,catch块和finally块至少要出现其中之一,也可以同时出现;

可以有多个catch块,捕获父类异常的catch块,必须位于捕获子类异常的后面;

多个catch块必须位于try块之后,finally块必须位于所有的catch块之后;

只有finally与try语句块的语法格式,这种情况会导致异常的丢失,所以并不常见;

通常情况下,我们不应该在finally代码块中使用return或throw等会导致方法终止的语句,否则这将会导致try和catch代码块中的return和throw语句失效。

尤其是try-catch-finally与return的结合,是我们面试时的一个考点哦。有些面试官会贱贱地问你try-catch-finally中如果有return,会发生什么,请大家自行做个实验吧。

4.2 代码实现

接下来在之前的案例基础上进行改造,引入finally代码块:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
 * @author 
 */
public class Demo03 {
    //try-catch-finally语句
    public static void main(String[] args) {
        //定义一个缓冲流对象,以后在IO流阶段壹哥会细讲
        BufferedReader reader = null;
        try {
        	//对接一个file.txt文件,该文件可能不存在
            reader = new BufferedReader(new FileReader("file.txt"));
            //读取文件中的内容。所有的IO流都可能会产生IO流异常
            String line = reader.readLine();
            while (line != null) {
                System.out.println(line);
                line = reader.readLine();
            }
        } catch (FileNotFoundException e) {
        	//处理文件不存在时的异常
            System.out.println("文件不存在:" + e.getMessage());
        } catch (IOException e) {
            //处理IO异常
            System.out.println("读取文件失败:" + e.getMessage());
        } finally {
            try {
                //在finally代码块中也可以进行try-catch的操作
                if (reader != null) {
                	//关闭IO流
                    reader.close();
                }
            } catch (IOException e) {
                System.out.println("关闭文件失败:" + e.getMessage());
            }
        }
	}
}

在这段代码中,我们尝试打开一个名为file.txt的文件,并逐行读取其内容。如果文件不存在或读取失败,程序将在相应的catch块中处理异常,并打印出异常消息。无论是否发生异常,程序都会在finally块中关闭文件。

4.3 小结

在try-catch-finally组合的结构中,其执行流程如下图所示:

根据该流程可知,try-catch-finally语句块的执行情况可以细分为以下几种情况:

如果try代码块中没有拋出异常,则执行完try代码块后会直接执行finally代码块;

如果try代码块中拋出了异常,并被catch子句捕捉,则终止try代码块的执行,转而执行相匹配的 catch代码块,之后再执行 finally代码块;

如果try代码块中拋出的异常没有被任何catch子句捕获到,将会直接执行finally代码块中的语句,并把该异常传递给该方法的调用者;

如果在finally代码块中也拋出了异常,则会把该异常传递给该方法的调用者。

二. 结语

至此,就把今天的内容讲解完毕了,通过今天的内容,大家要注意以下几点:

  • try...catch与if...else是不一样的,try后面的花括号{ }不可以省略,即便try中只有一行代码;
  • 同样的,catch的花括号 { } 也不可以省略
  • 当捕获的多个异常类之间存在父子关系时,一般是先捕获子类,再捕获父类;
  • 在异常处理的语法结构中,只有try是必需的。如果没有try代码块,则不能有后面的catch和finally。

以上就是学习Java之异常到底该如何捕获和处理的详细内容,更多关于Java异常捕获和处理的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot利用随机盐值实现密码的加密与验证

    SpringBoot利用随机盐值实现密码的加密与验证

    这篇文章主要为大家详细介绍了SpringBoot如何利用随机盐值实现密码的加密与验证,文中的示例代码讲解详细,有需要的小伙伴可以参考下
    2024-02-02
  • SpringBoot自动重启的两种方法

    SpringBoot自动重启的两种方法

    我们在项目开发阶段,可能经常会修改代码,修改完后就要重启Spring Boot,本文主要介绍了SpringBoot自动重启的两种方法,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • Java中的Native关键字讲解

    Java中的Native关键字讲解

    本文介绍了Java中的Native关键字,native关键字是架起本机语言和JAVA之间鸿沟的桥梁。如果我们的软件与硬件的交互在使用预先存在的代码时更有效,那么这可以作为一个关键环节。与从头开始设计新的应用程序代码相比,只要可以避免,它就可以使实现工作更少,下面来了解集体内容
    2021-12-12
  • 利用Java实现带GUI的气泡诗词特效

    利用Java实现带GUI的气泡诗词特效

    这篇文章主要为大家介绍了如何利用Java语言实现带GUI的气泡诗词特效,文中的示例代码讲解详细,对我们学习Java有一定帮助,感兴趣的可以了解一下
    2022-08-08
  • Springboot传参详解

    Springboot传参详解

    这篇文章主要介绍了Springboot传参的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-11-11
  • Spring Boot利用@Async如何实现异步调用:自定义线程池

    Spring Boot利用@Async如何实现异步调用:自定义线程池

    这篇文章主要给大家介绍了关于Spring Boot利用@Async如何实现异步调用:自定义线程池的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2018-05-05
  • MyBatis批量插入数据过程解析

    MyBatis批量插入数据过程解析

    这篇文章主要介绍了MyBatis批量插入数据过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • java基础之字符串编码知识点总结

    java基础之字符串编码知识点总结

    这篇文章主要介绍了java基础之字符串编码总结,文中有非常详细的代码示例,对正在学习java基础的小伙伴们有很好的帮助,要的朋友可以参考下
    2021-04-04
  • Spring Boot Actuator执行器运行原理详解

    Spring Boot Actuator执行器运行原理详解

    这篇文章主要介绍了Spring Boot Actuator执行器运行原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java中注解的常见用法总结

    Java中注解的常见用法总结

    注解(Annotation),也叫元数据,是JDK1.5及以后版本引入的一个特性,本文主要为大家介绍了注解的常见用法,需要的小伙伴可以参考一下
    2023-07-07

最新评论