Java 中的异常处理

news2024/11/28 6:45:31

认识异常

程序中可能会有很多意想不到的问题的出现,这些问题中,有些是在编写阶段时就无法编译通过,比如写代码时变量名写错,出现语法错误 java.lang.Error: Unresolved compilation problem ……;有些是在程序运行的时候出现的,比如一个除法程序,结果用户输入的除数是 0,那么就会引发 java.lang.ArithmeticException 等等。异常发生的原因很多,但无论怎样,这些异常和其他的对象一样,都只是类的实例。

异常分类

Java 中异常处理主要有三类:

  • 检查性异常(Checked Exception):检查一词可以理解为编译器对代码的检查,如果代码中含有此类异常且没有进行处理,编译就无法通过,比如文件无法找到的异常等。这种异常可以说是 Java 的特色,其他流行语言少有这种异常。这样的异常一般是由程序运行的环境所导致的,程序员无法知道程序最终的运行环境,所以应该时刻准备好应对这些异常(用 try ... catch ... 捕获并处理);
  • 运行时异常(Runtime Exception):这是编译器无法检查到,程序运行时才会出现的异常,比如除数为零这样的异常。对于这类异常,程序员应该先尝试直接修改代码的逻辑避免出现此类异常,实在不行时再用 try ... catch ... 去捕获它并进行处理。一个好的代码,应该尽可能少地抛出运行时异常;
  • 错误(Error):错误是 Java 程序无法处理的严重故障,程序员一般不应该去捕获它们,捕获了可能也无法处理,这也是程序员无法预见的,在编译时编译器也无法检查到,大部分错误都与程序员执行的操作无关,而是虚拟机本身在平台上的运行出现了问题。

下面是异常机制的继承关系图:

异常继承关系图

内置异常

Java 语言内置的标准异常类型都在 java.lang 标准包中。

运行时异常

下面只列出部分常用的运行时异常:

异常类型名描述
ArithmeticException当出现异常的运算条件时(如除数为零),抛出此异常
ArrayIndexOutOfBoundsException用非法索引(索引为负或大于等于数组大小)访问数组时,抛出此异常
ArrayStoreException试图将错误类型的对象存储到一个对象数组时,抛出此异常
ClassCastException当试图将对象强制转换为不是实例的子类时,抛出此异常
IllegalArgumentException向方法传递了一个不合法或不正确的参数时,抛出此异常
IllegalMonitorStateException抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程
IllegalStateException在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下
IllegalThreadStateException线程没有处于请求操作所要求的适当状态时抛出的异常
IndexOutOfBoundsException指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出
NegativeArraySizeException如果应用程序试图创建大小为负的数组,则抛出该异常
NullPointerException当应用程序试图在需要对象的地方使用 null 时,抛出该异常
NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常
SecurityException由安全管理器抛出的异常,指示存在安全侵犯
StringIndexOutOfBoundsException此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小
UnsupportedOperationException当不支持请求的操作时,抛出此异常

检查性异常

下面只列出部分检查性异常:

异常类型名描述
ClassNotFoundException应用程序试图加载类时,找不到相应的类,抛出该异常
CloneNotSupportedException当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常
IllegalAccessException拒绝访问一个类的时候,抛出该异常
InstantiationException当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常
InterruptedException一个线程被另一个线程中断,抛出该异常
NoSuchFieldException请求的变量不存在
NoSuchMethodException请求的方法不存在

错误

下面只列出部分错误类型:

错误类型名描述
LinkageError动态链接失败
VirtualMachineError虚拟机错误
AWTErrorAWT错误

异常的方法

这里只说明 Throwable 的方法,其子类异常还有其他自己的方法,这里不展开讲述。下面是 Throwable 类的主要方法:

方法名描述
public String getMessage()返回关于发生的异常的详细信息
public Throwable getCause()返回一个 Throwable 对象代表异常原因
public String toString()返回此 Throwable 的简短描述
public void printStackTrace()将此 Throwable 及其回溯打印到标准错误流
public StackTraceElement [] getStackTrace()返回一个包含堆栈层次的数组,下标为 0 的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底
public Throwable fillInStackTrace()用当前的调用栈层次填充 Throwable 对象栈层次,添加到栈层次任何先前信息中

捕获异常

try ... catch ... 语句

和 C++ 语言类似,使用 try 关键字和 catch 关键字捕获异常。在 try 语句块中的部分代码是可能出现异常的代码,catch 关键字后面表示捕获哪一种特殊的异常,并在其语句块中进行相应的处理。

try {
    // 某种异常
} catch (ExceptionType e) { // ExceptionType表示某种异常类型,e是这个异常实例对象的引用名
    // 处理方式
}

下面是一个使用 try ... catch ... 的示例:

public class Test {
    public static void main(String[] args) {
        System.out.println(divide(1, 0));
        // Output:
        // 除数不能为零!
        // 0
    }

    public static int divide(int num1, int num2) {
        try {
            return num1 / num2;
        } catch (ArithmeticException e) {
            System.out.println("除数不能为零!");
            return 0;
        }
    }
}

多重捕获

当异常类型不只一种的时候,就需要多重捕获。

try {
    // 某种异常
} catch (ExceptionType1 e1) {
    // 对于第一种异常的处理方式
} catch (ExceptionType2 e2) {
    // 对于第二种异常的处理方式
}

finally 关键字

这个 finally 关键字和 Python 异常处理中的 finally 关键字类似,都是在 try ... catch ... 语句执行完后执行 finally 关键字中的内容。

try {
    // 捕获异常
} catch (ExceptionType e) {
    // 处理异常
} finally {
    // 最后执行(不管上面是否对异常进行了处理)
}

下面和 Python 的异常处理进行对比:

""" Python 的异常处理 """
try:
    ...  # 捕获异常
except ExceptionType as e:  # e是异常类型的实例对象的引用变量名
    ...  # 处理异常
else:
    ...  # 没有异常时执行的代码
finally:
    ...  # 最后必定执行的代码

除了 else 是 Python 中特有的用法之外,其余部分和 Java 中的几乎完全相同。另外,标准 C++ 的异常处理中没有 finally 关键字(MSVC 中有个 __finally 关键字做了 finally 的替代,但其他的 C++ 编译器不一定有)

总结一下,下面是 try ... catch ... finally ... 语句的执行流程图:

try ... catch ... finally ... 语句

此外,还要注意以下几点:

  • catch 或者 finally 关键字不能独立于 try 关键字而存在;
  • 当不是 try-with-resources 语法时,try 后面必须接上 catch 或者 finally 关键字;
  • 多重捕获时,具体异常要放在宽泛异常之前,不然无法捕获到(逻辑上宽泛异常包含了具体异常);

try-with-resources 语法糖

try-with-resouces 语法糖是 Java 的一种特殊语法,是在 Java7 为了简化语法(方便打开资源)而引入的。在 Java7 之前,打开文件、套接字等,都需要程序员手动地去关闭这些资源,很麻烦,用 finally 也不方便。于是就在 Java7 出现了这个语法糖,它可以在执行完相关的操作后自动关闭这些资源。

该语法糖的基本格式如下:

try (resource_declaration_1; resource_declaration_2; ...) { // 圆括号内可声明或实例化一个或多个(用分号间隔)资源对象
    // 使用的资源
} // 执行完后,资源对象将被自动关闭,关闭顺序与声明或实例化顺序相反

下面是一个示例:

public static void try_with_res() throws IOException { // 下面产生的异常(被声明了)会传递到方法外部,相当于处理了(后面会讲)
    try (Scanner s = new Scanner(new File("input.txt")); PrintWriter w = new PrintWriter(new File("output.txt"))) {
        while (s.hasNext())
            w.print(s.nextLine());
    }
}

其实这个语法糖在资源打开操作方面和 Python 中的 with 关键字有异曲同工之妙,都可以简化资源的操作(打开后自动关闭),下面给出一个示例(Python3.8)以进行对比:

with open('input.txt', 'r') as input_file, open('output.txt', 'w') as output_file:
    while line := input_file.readline():
        output_file.write(line)

抛出异常和声明异常

throw 关键字

程序员可以用 throw 关键字来显式地抛出异常。

throw new ExceptionObject(...);

下面是一个示例:

public static void CheckArgument(Object arg) {
    if (arg instanceof Integer) {
        throw new IllegalArgumentException("参数类型不能为整型!");
    }
}

throws 关键字

程序员可以用 throws 关键字来为方法声明可能抛出的异常,这只是一个声明,并非运行时一定抛出该异常。当该方法中真的抛出声明中指定的异常时,此异常就会向外传递到方法外部,也就是调用该方法的地方。throws 关键字放在方法头之后,花括号之前,后面跟要声明的异常,可以有多个,通过逗号间隔。

下面是一个示例:

public static void CheckArgument(Object arg) throws IllegalArgumentException, UnknownError {
    if (arg instanceof Integer) {
        throw new IllegalArgumentException("参数类型不能为整型!");
    }
}

自定义异常

程序员除了可以使用 Java 内置的异常之外,还可以自己定义一个异常来使用,但无论怎样,自定义的异常也是异常最顶层父类 Throwable 的子类。用途的不同的异常,需要继承的父类异常也不一样,若是要自定义运行时异常,则应该继承类 RuntimeException;若是检查性异常,则应该继承类 Exception;若是错误,则应该继承类 Error。

自定义的异常类型和其他的异常一样,实际都是对象。自定义的异常一般应该满足以下条件,当然,这不是强制的:

  • 有一个无参构造函数;
  • 有一个带有 String 参数的构造函数,并传递给父类的构造函数;
  • 有一个带有 Throwable 参数的构造函数,并传递给父类的构造函数;
  • 有一个带有 String 参数和 Throwable 参数,并都传递给父类构造函数;

下面是一个自定义异常的简单示例:

class ZeroDivisionException extends ArithmeticException {
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/646746.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从零开始Vue项目中使用MapboxGL开发三维地图教程(四)改变鼠标style、地图置于单击feature中心、量测距离和polgon面积和中心点坐标

文章目录 1、飞行平移到鼠标点击图层属性的地图中心位置2、当鼠标光标进入“圆”图层中的某个要素时,将其更改为指针3、量测距离4、量测area面积和中心点坐标 1、飞行平移到鼠标点击图层属性的地图中心位置 //鼠标点击事件map.on("click", "iconImag…

基于Amazon SageMaker平台部署Stable Diffusion模型实现——图片识别

序言: 当谈到机器学习和人工智能的开发和部署时,Amazon SageMaker是一个非常强大和全面的平台。作为一项托管式的机器学习服务,Amazon SageMaker提供了一套完整的工具和功能,帮助开发者轻松构建、训练和部署机器学习模型。 首先&…

程序猿成长之路之密码学篇-AES算法解密详解及代码呈现

各位csdn的小伙伴们大家好呀,我又回来了,这篇文章为上一次介绍AES加密算法的姊妹篇,重点将会详细介绍一下AES算法的解密过程并呈上AES加解密的代码。【暂时不包含iv即偏移量】。下面请跟随我一同进入AES解密的世界。 AES加密详解 如果有小伙…

ffmpeg编译笔记:ubuntu18.04编译ffmpeg5.1 x86与64

一、前言 本篇描述了ffmpeg5.1在ubuntu18.04上的编译经验。编译后的库支持h264,h265软硬解码,支持https,支持SDL。本篇同时描述openssl在ffmpeg中的编译经验,以及提供ffmpeg编译和openssl编译的32位和64位的配置命令。 二、相关…

这8道接口测试面试题

接口测试常见的问题了。 大家乍一看! 接口测试面试题 这几个问题,能答出来几个?有没有8个都能够完美的答出来的?在留言区打出你的数字。(0~8) 这些问题你回答起来,不要吞吞吐吐只说几个关键字…

1. java.io.File 类的使用

1.1 概述 • File 类及本章下的各种流,都定义在 java.io 包下。 • 一个 File 对象代表硬盘或网络中可能存在的一个文件或者文件目录(俗称文件夹), 与平台无关。(体会万事万物皆对象) • File 能新建、删除…

重启好多次路由器,还是上不了网怎么办?

大家好,我的网工朋友 遇到突发的网络断连,你一般会怎么做? 我觉得很多人都会插拔一下路由器,这和电脑不行了,马上就重启电脑一样,是刻在DNA里的傻瓜操作。 但是也有很多时候,这个傻瓜操作是解…

PrivateGPT:安全和私密的离线 GPT-4

在人工智能 (AI) 和自然语言处理 (NLP) 领域,隐私通常是一个基本问题,尤其是在处理敏感数据时。PrivateGPT 是这一领域的突破性发展,正面解决了这个问题。它旨在在没有互联网连接的情况下在本地运行,通过防止数据离开您的执行环境…

这些方法可以手写扫描识别

小伙伴们知道有一项技术是可以将我们手写的东西识别出来吗?这一项创新的技术就是手写识别功能,它能够将手写内容快速转换为数字或文本格式,并提高信息处理和管理的效率。而且相比传统的手工记录方式,手写识别功能具有较高的准确性…

腾讯测试开发 4 轮面试,接到 30k*15 的 Offer !详解面试流程和真题

在互联网做了几年之后,去大厂“镀镀金”是大部分人的首选。大厂不仅待遇高、福利好,更重要的是,它是对你专业能力的背书,大厂工作背景多少会给你的简历增加几分竞争力。 但说实话,想进大厂还真没那么容易。我的一个朋…

find命令

你将看到的第一个命令是find。这是个用于搜索文件的命令,它极其有用,但Linux初学者常常觉得它不易使用,这不仅仅是因为它有选项、测试和动作类型的参数,还因为其中一个参数的处理结果可能会影响到后续参数的处理。在深入研究这些选…

pandas---缺失值的处理

1. 处理缺失值 判断数据中是否包含NaN: pd.isnull(df);pd.notnull(df) 存在缺失值nan: 删除存在缺失值的:dropna(axisrows) 不会修改原数据,需要接受返回值; 替换缺失值:fillna(value, inplaceTrue) value:替换成的值&#…

基于STM32的四旋翼无人机项目(一):基础知识篇

前言:本篇博客为飞控专栏的第一篇系统性概述文章,将对飞控系统进行详细讲解介绍。考虑到飞控项目具有一定工程复杂度,所以作者将整个项目进行分章节教学与讲解,希望可以给读者朋友带来更好地学习体验。项目将以 C-Quad 四轴无人机…

SpringBoot 中使用 JWT 案例分享详解

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…

大模型LLM领域,有哪些可以作为学术研究方向?

清湛人工智能研究院 2023-05-31 09:23 发表于江苏 编者:本文转载了清华大学计算机系刘知远教授对大模型的一些思索,以飨读者。 刘知远 CCF 高级会员,CCCF 前编委。清华大学计算机系副教授、博士生导师。已在ACL、IJCAI、AAAI等人工智能领域…

回归预测 | MATLAB实现基于GRU-AdaBoost门控循环单元结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于GRU-AdaBoost门控循环单元结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于GRU-AdaBoost门控循环单元结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于GRU-AdaBoost门…

单品GMV破千万,这些品类正在抖音热卖

优势品类及核心产品能更好触达消费者,以较低的成本让用户感知品牌,塑造品牌力。 抖音作为品牌最核心的线上渠道之一,该如何找到平台优势品类?制定品牌营销策略?有效提升产品销量呢? 近期,新抖上…

【CesiumJS入门】(4)加载3D Tiles并获取tileset

前言 本次,我们将写一个函数来加载3D Tiles数据, 3D Tiles数据的文档:CesiumGS/3d-tiles: Specification for streaming massive heterogeneous 3D geospatial datasets (github.com) 同时我们将获取加载成功后的tileset数据集(有…

Python 中错误 ImportError: No Module Named Sklearn

在 Python 中,sklearn 被用作机器学习工具,用于在回归、集群等方面创建程序。很多时候,导入它会抛出错误—— No module named sklearn。 这意味着由于安装错误、无效的 Python 或 pip 版本或其他问题,系统无法找到它。 Python中错误ImportError: No module named sklearn…

基于Java营业厅宽带系统设计实现(源码+lw+部署文档+讲解等)

博主介绍: ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ 🍅 文末获取源码联系 🍅 👇🏻 精…