百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Java 基础(十二)异常机制 java中的异常处理机制的简单原理和应用

lipiwang 2024-10-23 14:02 7 浏览 0 评论


异常

一说谈到异常,可能就有小伙伴说,这个啊,我 try...catch...finally用得贼溜。别急哈,后面有个 案例,看完之后你肯定会觉得自己对异常的理解也不是那么透彻了,同时本文还可能会扫到你的一些知识盲点。额,扯远了~

异常一般指不期而至的各种状况,如:文件不存在、空指针、非法参数等。异常是一个事件,发生在程序运行期间,干扰了正常的指令流程。Java 中使用 Throwable 类及其子类来描述各种不同的异常。因此,Java 异常都是对象,是 Throwable 的子类实例,描述了出现在一段编码中的错误条件。当条件生成时,错误将引发异常。

Java 异常类层次结构图:

从图上我们可以看到,Java 异常都继承自 Throwable,Throwable 分为两大派系,一类是 Error(错误),一类是 Exception(异常)。

Error

Error 是程序员无法处理的错误,表示运行应用程序中较严重的问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM 出现的问题。比如,Java 虚拟机运行时错误(VirtualMachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这时异常发生时,Java 虚拟机一般会终止线程。

所以这一类异常我们一般不用太纠结。

Exception

这是程序本身可以处理的异常。Exception 有一个非常重要的子类 RuntimeException,RuntimeException 类及其子类表示 JVM 常用操作引发的错误,例如空值对象引用、除数为零、数组角标越界则分别会引发 NullPointException、ArithmeticException、ArrayIndexOutOfBoundException。

敲黑板!!分清异常和错误的区别,异常是可以被程序本身处理的,错误不能。

可查异常

又称编译时异常,是编译器要求必须处置的异常。正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。

除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

不可查异常

编译器不要求强制处置的异常,包括运行时异常(RuntimeException)和错误(Error)。

运行时异常

都是 RuntimeException 类及其子类。

这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。

编译时异常

是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。

处理异常机制

遇到异常怎么办?要么自己想办法处理,要么就抛给别人。

抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交付给运行时系统,系统对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。

捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(Exception handler)。潜在的异常处理是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与抛出的异常类型相符时,即为合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有异常处理器的方法并执行。当运行时系统遍历了调用栈都没找到合适的异常处理器,则运行时系统终止,Java 程序终止。

对于运行时异常、错误和可查异常,Java 要求的异常处理方式有所不同。

  • 对于方法运行中可能出现的 Error,当运行方法不能捕捉时,Java 允许该方法不做任何抛出声明。因为大多数 Error 异常属于永远不允许发生的情况,也属于合理的应用程序不挂捕获的异常。
  • 对于所有可查异常,Java 规定:一个方法必须捕捉或者声明抛出。

能够捕捉异常的方法,需要提供相符类型的异常处理器。也就是说,一个方法所能捕获的异常,一点是 Java 代码在某处所抛出的异常。

任何Java代码都可以抛出异常,如:自己编写的代码、来自Java开发环境包中代码,或者Java运行时系统。无论是谁,都可以通过Java的throw语句抛出异常。

从方法中抛出的任何异常都必须使用throws子句。

捕捉异常通过try-catch语句或者try-catch-finally语句实现。

总结来说。Java 规定:对于可查异常必须捕捉、或者声明抛出。运行忽略不可查的 RuntimeException 和 Error。

捕获异常 try、catch 和 finally

  • 首先是 try-catch 语句

基本语法如下:

Bash
try {  
    // 可能会发生异常的程序代码  
} catch (Type1 id1){  
    // 捕获并处置try抛出的异常类型Type1  
} catch (Type2 id2){  
     //捕获并处置try抛出的异常类型Type2  
}

关键词 try 后面的大括号区域为可能发生异常的代码,称为监控区。当抛出异常或者出现运行时异常,然后由 Java 运行时系统巡展匹配 catch 子句。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。

匹配规则:抛出的异常属于 catch 语句捕获异常类及子类,则匹配成功。

需要注意的是:一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的catch子句不再有匹配和捕获异常类型的机会,并且 try 里面如果有没有走完的语句也会自动跳过

  • try-catch-finally

这个很简单,无论 try-catch 是正常结束还是发生异常捕获,都会执行 finally 语句,如果在 finally 之前发生了 return,那么 finally 语句块会在 retrun 之前执行。

小结:

try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。catch 块:用于处理try捕获到的异常。finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。finally 如果有 return 会覆盖 catch 里的throw,同样如果 finally 里有 throw 会覆盖 catch 里的 return。

try-catch-finally 规则

1.必须在 try 后面添加 catch 或 finally。可以同时存在,catch 块也可以有多个,但是 catch 必须放在 try 块或者 catch 块后面。2.try-catch-finally 可以嵌套3.在 try-catch-finally 结构中,可以重新抛出异常4.除非 finally 中抛出异常或者 JVM 停止运行,否则都会执行 finally 语句

try-catch-finally 语句执行顺序1.当 try 没有捕获到异常时:try 语句正常执行,程序跳过 catch 语句,执行 finally。

2.当 try 捕获到异常时,catch 没有匹配上异常,则交给 JVM 处理,finally 语句块还是会被执行,但是 finally 之后的语句不会被执行了。

3.当 try 捕获到异常,catch 匹配上了,则按照 try-catch-finally 的正常顺序执行,但是 try 里面异常语句之后的语句不会被执行。

抛出异常

任何 Java 代码都可以抛出异常,语句通过 throw 抛出、方法则是 throws。

为什么要 throw 异常?

如果一个方法可能会出现异常,但是没有能力处理这种又一次,则可以在方法声明处用 throws 语句来抛出。

throws 语句可以同时声明抛出多个异常,语法格式如下

Bash
void methodName()throws Exception1,Exception2,Exception3{
}

就酱紫。此时这个方法就不用对方法重点问这些异常做任何处理,但是调用这个方法的语句必须要处理,要么继续抛,要么 try-catch。

Throws 抛出规则

1.如果是不可查异常,那么不用声明,编译仍然可以通过,但是运行时会被JVM 抛出2.如果是可查异常,要么 try-catch,要么 throws,否则编译无法通过。3.当抛出了异常时,该方法的调用者才会处理或者重新抛出该异常。4.调用 throws 异常的方法,必须 try-catch 调用语气,且 catch 的异常必须是抛出异常的同类或者父类。

Throw 抛出异常这个真没什么好说的了,想抛或者需要抛,就直接调用就行了,注意 throw 后面只能接 Throwable 的子类。

Throwable 类常用方法

这个本应该在开篇就讲的,但是好像都不怎么常用,所以就放在这里查漏补缺吧

Java 常见的异常

  • 运行时异常1.ArrayIndexOutOfBoundException数组索引越界异常。2.ArithmeticException算术条件异常,如除数为03.NullPointException空指针异常。4.ClassNotFoundException找不到类异常。5.NegativeArraySizeException数组长度为负异常6.ArrayStoreException数组中包含不兼容的值抛出异常7.SecurityException安全性异常8.IllegalArgumentException非法参数异常
  • IOException1.IOException操作输入流和输出流可能出现的异常2.EOFException文件已结束异常3.FileNotFoundException文件未找到异常
  • 其他
    1.ClassCastException
    类型转换异常类
    2.ArrayStoreException
    数组中包含不兼容的值抛出的异常
    3.SQLException
    操作数据库异常类
    4.NoSuchFieldException
    字段未找到异常
    5.NoSuchMethodException
    方法未找到抛出的异常
    6.NumberFormatException
    字符串转换为数字抛出的异常
    7.StringIndexOutOfBoundsException
    字符串索引超出范围抛出的异常
    8.IllegalAccessException
    不允许访问某类异常
    9.InstantiationException
    当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常

自定义异常

使用Java 内置的异常类可以描述在编程中出现的大部分情况,除此之外,用户还可以自定义异常。自定义异常类,只需要继承 Exception 即可。

在程序中使用自定义异常类,大体可分为以下几个步骤。

1.创建自定义异常类。2.在方法中通过throw关键字抛出异常对象。3.如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。4.在出现异常方法的调用者中捕获并处理异常。

练习

异常差不多就到这里吧,做完这个小练习,如果能做对的话就差不多了,如果做不对,那再回过头去重新读一遍这篇文章。

//执行语句
TestException testException1 = new TestException();
    try {
        testException1.testEx();
    } catch (Exception e) {
        e.printStackTrace();
    }

//异常类
public class TestException {
    public TestException() {
    }

    boolean testEx() throws Exception {
        boolean ret = true;
        try {
            ret = testEx1();
        } catch (Exception e) {
            Log.e("sss___sss","testEx, catch exception");
            ret = false;
            throw e;
        } finally {
            Log.e("sss___sss","testEx, finally; return value=" + ret);
            return ret;
        }
    }

    boolean testEx1() throws Exception {
        boolean ret = true;
        try {
            ret = testEx2();
            if (!ret) {
                return false;
            }
            Log.e("sss___sss","testEx1, at the end of try");
            return ret;
        } catch (Exception e) {
            Log.e("sss___sss","testEx1, catch exception");
            ret = false;
            throw e;
        } finally {
            Log.e("sss___sss","testEx1, finally; return value=" + ret);
            return ret;
        }
    }

    boolean testEx2() throws Exception {
        boolean ret = true;
        try {
            int b = 12;
            int c;
            for (int i = 2; i >= -2; i--) {
                c = b / i;
                Log.e("sss___sss","i=" + i);
            }
            return true;
        } catch (Exception e) {
            Log.e("sss___sss","testEx2, catch exception");
            ret = false;
            throw e;
        } finally {
            Log.e("sss___sss","testEx2, finally; return value=" + ret);
            return ret;
        }
    }
}

求以上语句的答应结果~

自己先读一遍,再来对答案哦~

sss___sss: i=2
sss___sss: i=1
sss___sss: testEx2, catch exception
sss___sss: testEx2, finally; return value=false
sss___sss: testEx1, finally; return value=false
sss___sss: testEx, finally; return value=false

好了,异常机制的学习就到这里吧。

相关推荐

linux实例之设置时区的方式有哪些

linux系统下的时间管理是一个复杂但精细的功能,而时区又是时间管理非常重要的一个辅助功能。时区解决了本地时间和UTC时间的差异,从而确保了linux系统下时间戳和时间的准确性和一致性。比如文件的时间...

Linux set命令用法(linux cp命令的用法)

Linux中的set命令用于设置或显示系统环境变量。1.设置环境变量:-setVAR=value:设置环境变量VAR的值为value。-exportVAR:将已设置的环境变量VAR导出,使其...

python环境怎么搭建?小白看完就会!简简单单

很多小伙伴安装了python不会搭建环境,看完这个你就会了Python可应用于多平台包括Linux和MacOSX。你可以通过终端窗口输入"python"命令来查看本地是否...

Linux环境下如何设置多个交叉编译工具链?

常见的Linux操作系统都可以通过包管理器安装交叉编译工具链,比如Ubuntu环境下使用如下命令安装gcc交叉编译器:sudoapt-getinstallgcc-arm-linux-gnueab...

JMeter环境变量配置技巧与注意事项

通过给JMeter配置环境变量,可以快捷的打开JMeter:打开终端。执行jmeter。配置环境变量的方法如下。Mac和Linux系统在~/.bashrc中加如下内容:export...

C/C++|头文件、源文件分开写的源起及作用

1C/C++编译模式通常,在一个C++程序中,只包含两类文件——.cpp文件和.h文件。其中,.cpp文件被称作C++源文件,里面放的都是C++的源代码;而.h文件则被称...

linux中内部变量,环境变量,用户变量的区别

unixshell的变量分类在Shell中有三种变量:内部变量,环境变量,用户变量。内部变量:系统提供,不用定义,不能修改环境变量:系统提供,不用定义,可以修改,可以利用export将用户变量转为环...

在Linux中输入一行命令后究竟发生了什么?

Linux,这个开源的操作系统巨人,以其强大的命令行界面而闻名。无论你是初学者还是经验丰富的系统管理员,理解在Linux终端输入一条命令并按下回车后发生的事情,都是掌握Linux核心的关键。从表面上看...

Nodejs安装、配置与快速入门(node. js安装)

Nodejs是现代JavaScript语言产生革命性变化的一个主要框架,它使得JavaScript从一门浏览器语言成为可以在服务器端运行、开发各种各样应用的通用语言。在不同的平台下,Nodejs的安装...

Ollama使用指南【超全版】(olaplex使用方法图解)

一、Ollama快速入门Ollama是一个用于在本地运行大型语言模型的工具,下面将介绍如何在不同操作系统上安装和使用Ollama。官网:https://ollama.comGithub:http...

linux移植(linux移植lvgl)

1uboot移植l移植linux之前需要先移植一个bootlader代码,主要用于启动linux内核,lLinux系统包括u-boot、内核、根文件系统(rootfs)l引导程序的主要作用将...

Linux日常小技巧参数优化(linux参数调优)

Linux系统参数优化可以让系统更加稳定、高效、安全,提高系统的性能和使用体验。下面列出一些常见的Linux系统参数优化示例,包括修改默认配置、网络等多方面。1.修改默认配置1.1修改默认编辑器默...

Linux系统编程—条件变量(linux 条件变量开销)

条件变量是用来等待线程而不是上锁的,条件变量通常和互斥锁一起使用。条件变量之所以要和互斥锁一起使用,主要是因为互斥锁的一个明显的特点就是它只有两种状态:锁定和非锁定,而条件变量可以通过允许线程阻塞和等...

面试题-Linux系统优化进阶学习(linux系统的优化)

一.基础必备优化:1.关闭SElinux2.FirewalldCenetOS7Iptables(C6)安全组(阿里云)3.网络管理服务||NetworkManager|network...

嵌入式Linux开发教程:Linux Shell

本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...

取消回复欢迎 发表评论: