2023年11月29日发(作者:)

Java常见异常(RuntimeException)详细介绍并总结

本⽂重在Java中异常机制的⼀些概念。写本⽂的⽬的在于⽅便我很长时间后若是忘了这些东西可以通过这篇⽂章迅速回忆起

来。

1. 异常机制

1.1 异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序

执⾏的流程发⽣改变,程序的控制权转移到异常处理器。

1.2 传统的处理异常的办法是,函数返回⼀个特殊的结果来表⽰出现异常(通常这个特殊结果是⼤家约定俗称的),调⽤该函

数的程序负责检查并分析函数返回的结果。这样做有如下的弊端:例如函数返回-1代表出现异常,但是如果函数确实要返回-1

这个正确的值时就会出现混淆;可读性降低,将程序代码与处理异常的代码混爹在⼀起;由调⽤函数的程序来分析错误,这就

要求客户程序员对库函数有很深的了解。

1.3 异常处理的流程

1.3.1 遇到错误,⽅法⽴即结束,并不返回⼀个值;同时,抛出⼀个异常对象

1.3.2 调⽤该⽅法的程序也不会继续执⾏下去,⽽是搜索⼀个可以处理该异常的异常处理器,并执⾏其中的代码

2 异常的分类

2.1 异常的分类

2.1.1 异常的继承结构:基类为ThrowableErrorException继承ThrowableRuntimeExceptionIOException等继承

Exception,具体的RuntimeException继承RuntimeException

2.1.2 ErrorRuntimeException及其⼦类成为未检查异常(unchecked),其它异常成为已检查异常(checked)。

2.2 每个类型的异常的特点

2.2.1 Error体系 Error类体系描述了Java运⾏系统中的内部错误以及资源耗尽的情形。应⽤程序不应该抛出这种类型的对象

(⼀般是由虚拟机抛出)。如果出现这种错误,除了尽⼒使程序安全退出外,在其他⽅⾯是⽆能为⼒的。所以,在进⾏程序设

计时,应该更关注Exception体系。

2.2.2 Exception体系 Exception体系包括RuntimeException体系和其他⾮RuntimeException的体系

2.2.2.1 RuntimeException RuntimeException体系包括错误的类型转换、数组越界访问和试图访问空指针等等。处理

RuntimeException的原则是:如果出现RuntimeException,那么⼀定是程序员的错误。例如,可以通过检查数组下标和数组

边界来避免数组越界访问异常。

2.2.2.2 其他(IOException等等)这类异常⼀般是外部错误,例如试图从⽂件尾后读取数据等,这并不是程序本⾝的错误,⽽

是在应⽤环境中出现的外部错误。

2.3 C++异常分类的不同

2.3.1 其实,JavaRuntimeException这个类名起的并不恰当,因为任何异常都是运⾏时出现的。(在编译时出现的错误并不

是异常,换句话说,异常就是为了解决程序运⾏时出现的的错误)。

2.3.2 C++logic_errorJava中的RuntimeException是等价的,⽽runtime_errorJava中⾮RuntimeException类型的异常是

等价的。

3 异常的使⽤⽅法

3.1 声明⽅法抛出异常

3.1.1 语法:throws(略)

3.1.2 为什么要声明⽅法抛出异常?⽅法是否抛出异常与⽅法返回值的类型⼀样重要。假设⽅法抛出异常确没有声明该⽅法将

抛出异常,那么客户程序员可以调⽤这个⽅法⽽且不⽤编写处理异常的代码。那么,⼀旦出现异常,那么这个异常就没有合适

的异常控制器来解决。

3.1.3 为什么抛出的异常⼀定是已检查异常? RuntimeExceptionError可以在任何代码中产⽣,它们不需要由程序员显⽰的

抛出,⼀旦出现错误,那么相应的异常会被⾃动抛出。⽽已检查异常是由程序员抛出的,这分为两种情况:客户程序员调⽤会

抛出异常的库函数(库函数的异常由库程序员抛出);客户程序员⾃⼰使⽤throw语句抛出异常。遇到Error,程序员⼀般是⽆

能为⼒的;遇到RuntimeException,那么⼀定是程序存在逻辑错误,要对程序进⾏修改(相当于调试的⼀种⽅法);只有已

检查异常才是程序员所关⼼的,程序应该且仅应该抛出或处理已检查异常。

3.1.4 注意:覆盖⽗类某⽅法的⼦类⽅法不能抛出⽐⽗类⽅法更多的异常,所以,有时设计⽗类的⽅法时会声明抛出异常,但

实际的实现⽅法的代码却并不抛出异常,这样做的⽬的就是为了⽅便⼦类⽅法覆盖⽗类⽅法时可以抛出异常。

3.2 如何抛出异常

3.2.1 语法:throw(略)

3.2.2 抛出什么异常?对于⼀个异常对象,真正有⽤的信息时异常的对象类型,⽽异常对象本⾝毫⽆意义。⽐如⼀个异常对象

的类型是ClassCastException,那么这个类名就是唯⼀有⽤的信息。所以,在选择抛出什么异常时,最关键的就是选择异常

的类名能够明确说明异常情况的类。

3.2.3 异常对象通常有两种构造函数:⼀种是⽆参数的构造函数;另⼀种是带⼀个字符串的构造函数,这个字符串将作为这个

异常对象除了类型名以外的额外说明。

3.2.4 创建⾃⼰的异常:当Java内置的异常都不能明确的说明异常情况的时候,需要创建⾃⼰的异常。需要注意的是,唯⼀有

⽤的就是类型名这个信息,所以不要在异常类的设计上花费精⼒。

3.3 捕获异常如果⼀个异常没有被处理,那么,对于⼀个⾮图形界⾯的程序⽽⾔,该程序会被中⽌并输出异常信息;对于⼀个

图形界⾯程序,也会输出异常的信息,但是程序并不中⽌,⽽是返回⽤户界⾯处理循环中。

3.3.1 语法:trycatchfinally(略)控制器模块必须紧接在try块后⾯。若掷出⼀个异常,异常控制机制会搜寻参数与异常类

型相符的第⼀个控制器随后它会进⼊那个catch 从句,并认为异常已得到控制。⼀旦catch 从句结束对控制器的搜索也会停

⽌。

3.3.1.1 捕获多个异常(注意语法与捕获的顺序)(略)

3.3.1.2 finally的⽤法与异常处理流程(略)

3.3.2 异常处理做什么?对于Java来说,由于有了垃圾收集,所以异常处理并不需要回收内存。但是依然有⼀些资源需要程序

员来收集,⽐如⽂件、⽹络连接和图⽚等资源。

3.3.3 应该声明⽅法抛出异常还是在⽅法中捕获异常?原则:捕捉并处理哪些知道如何处理的异常,⽽传递哪些不知道如何处

理的异常

3.3.4 再次抛出异常

3.3.4.1 为什么要再次抛出异常?在本级中,只能处理⼀部分内容,有些处理需要在更⾼⼀级的环境中完成,所以应该再次抛

出异常。这样可以使每级的异常处理器处理它能够处理的异常。

3.3.4.2 异常处理流程对应与同⼀try块的catch块将被忽略,抛出的异常将进⼊更⾼的⼀级。

4 关于异常的其他问题

4.1 过度使⽤异常⾸先,使⽤异常很⽅便,所以程序员⼀般不再愿意编写处理错误的代码,⽽仅仅是简简单单的抛出⼀个异

常。这样做是不对的,对于完全已知的错误,应该编写处理这种错误的代码,增加程序的鲁棒性。另外,异常机制的效率很

差。

4.2 将异常与普通错误区分开对于普通的完全⼀致的错误,应该编写处理这种错误的代码,增加程序的鲁棒性。只有外部的不

能确定和预知的运⾏时错误才需要使⽤异常。

4.3 异常对象中包含的信息⼀般情况下,异常对象唯⼀有⽤的信息就是类型信息。但使⽤异常带字符串的构造函数时,这个字

符串还可以作为额外的信息。调⽤异常对象的getMessage()toString()或者printStackTrace()⽅法可以分别得到异常对象的额

外信息、类名和调⽤堆栈的信息。并且后⼀种包含的信息是前⼀种的超集。

常⽤异常:

UnsupportedOperationException不⽀持的操作

IllegalArgumentException⾮法参数

IndexOutOfBoundsException索引出界

的代码将得不到正确的执⾏。甚⾄还会触发数据库的回退操作。

Java开发平台中,异常包括预定义异常与⾃定义异常。这两种异常的类型互为补充。作为⼀个合格的程序开发⼈员,要

善于在应⽤程序中使⽤异常。这可以提⾼应⽤程序的交互性。同时,也是保证应⽤程序正常运⾏的前提。故异常的处理对于开

发⼀个优秀的应⽤程序来说⾮常的重要。为此笔者认为程序开发⼈员应该对Java应⽤程序的常见异常有⼀个深⼊的了解。只

有在了解这些常见异常的情况下,才能够做好⾃定义异常的处理。

⼀、常见异常的类型与原因。

对于Java应⽤程序的常见异常,笔者认为程序开发⼈员要从两个⽅⾯去了解。⼀是要知道有哪些常见的Java应⽤程序异

常,⼆是需要知道哪些原因可能会造成这个异常。这不仅需要程序管理⼈员在⽇常⼯作中要注意积累,在必要的情况下还需要

去从其它渠道收集资料。笔者对此就进⾏⼀个分析,希望能够对各位程序开发⼈员有⼀定的帮助。

1 SQLException:操作数据库异常类。

现在的Java应⽤程序⼤部分都是依赖于数据库运⾏的。当Java应⽤程序与数据库进⾏沟通时如果产⽣了错误,就会触发这

个类。同时会将数据库的错误信息通过这个类显⽰给⽤户。也就是说,这个操作数据库异常类是数据库与⽤户之间异常信息传

递的桥梁。如现在⽤户往系统中插⼊数据,⽽在数据库中规定某个字段必须唯⼀。当⽤户插⼊数据的时候,如果这个字段的值

跟现有的纪录重复了,违反了数据库的唯⼀性约束,此时数据库就会跑出⼀个异常信息。这个信息⼀般⽤户可能看不到,因为

其发⽣在数据库层⾯的。此时这个操作数据库异常类就会捕捉到数据库的这个异常信息,并将这个异常信息传递到前台。如此

的话,前台⽤户就可以根据这个异常信息来分析发⽣错误的原因。这就是这个操作数据库异常类的主要⽤途。在Java应⽤程

序中,所有数据库操作发⽣异常时,都会触发这⼀个类。所有此时Java应⽤程序本⾝的提⽰信息往往过于笼统,只是说与数

据库交互出现错误,没有多⼤的参考价值。此时反⽽是数据库的提⽰信息更加有使⽤价值。

2 ClassCastException:数据类型转换异常。

Java应⽤程序中,有时候需要对数据类型进⾏转换。这个转换包括显⽰的转换与隐式的转换。不过⽆论怎么转换,都必

须要符合⼀个前提的条件,即数据类型的兼容性。如果在数据转换的过程中,违反了这个原则,那么就会触发数据类型转换异

常。如现在在应⽤程序中,开发⼈员需要将⼀个字符型的⽇期数据转换为数据库所能够接受的⽇期型数据,此时只需要在前台

应⽤程序中进⾏控制,⼀般不会有问题。但是,如果前台应⽤程序缺乏相关的控制,如⽤户在输⼊⽇期的时候只输⼊⽉、⽇信

息,⽽没有年份的信息。此时应⽤程序在进⾏数据类型转换的时候,就会出现异常。根据笔者的经验,数据类型转换异常在应

⽤程序开发中使⼀个出现的⽐较多的异常,也是⼀个⽐较低级的异常。因为⼤部分情况下,都可以在应⽤程序窗⼝中对数据类

型进⾏⼀些强制的控制。即在数据类型进⾏转换之前,就保证数据类型的兼容性。如此的话,就不容易造成数据类型的转换异

常。如在只允许数值类型的字段中,可以设置不允许⽤户输⼊数值以外的字符。虽然说有了异常处理机制,可以保证应⽤程序

不会被错误的运⾏。但是在实际开发中,还是要尽可能多的预见错误发⽣的原因,尽量避免异常的发⽣。

3 NumberFormatException:字符串转换为数字类型时抛出的异常。

在数据类型转换过程中,如果是字符型转换为数字型过程中出现的问题,对于这个异常在Java程序中采⽤了⼀个独⽴的异

常,即NumberFormatException.如现在讲字符型的数据“123456”转换为数值型数据时,是允许的。但是如果字符型数据中包

含了⾮数字型的字符,如123#56,此时转换为数值型时就会出现异常。系统就会捕捉到这个异常,并进⾏处理。

Java应⽤程序中常见的异常类还有很多。如未找到相应类异常、不允许访问某些类异常、⽂件已经结束异常、⽂件未找到异

常、字段未找到异常等等。⼀般系统开发⼈员都可以根据这个异常名来判断当前异常的类型。虽然不错,但是好记性不如烂笔

头。程序开发⼈员在必要的时候(特别是存在⾃定义异常的时候),最后⼿头有⼀份异常明细表。如此的话,⽆论是应⽤程序

在调试过程中发现问题,还是运⾏过程中接到⽤户的投诉,都可以及时的根据异常名字来找到异常发⽣的原因。从⽽可以在最

短时间内解决异常,恢复应⽤程序的正常运⾏。这个措施笔者⽤了很多年,⾮常的有效。

⼆、异常管理的实⽤建议。

对于操作数据库异常来说,Java应⽤程序只提供了⼀个异常类。故光凭Java应⽤程序的错误信息,往往不能够帮助应⽤程

序⼈员排除错误的原因。只能够指名是应⽤程序错误还是数据库错误导致的这个异常。为了更进⼀步指明问题的原因,在数据

库层⾯定义异常的时候,最好能够说明具体的原因。如前台应⽤程序可能会调⽤数据库的函数或者过程。此时在数据库的函数

或者过程中做好能够说明某个异常的具体原因。如根据某个基础表⽣成另⼀张表的时候,某个字段不能够为空等等。将这些异

常信息说明清楚后,如果真的遇到类似的异常时,操作数据库异常类就会将数据库的异常信息反会给前台⽤户。从⽽有利于⽤

户寻找问题的原因,并在最短时间内改正。当然,这需要Java程序员与数据库设计⼈员进⾏协调。

其次需要注意的是,异常并不是常态。也就是说,⼤部分异常可以通过前提的合理预见与预防,来消除。如设计到四则运

算,可以在前台应⽤程序窗⼝中限制在除数字段内输⼊0值等⼿段来消除应⽤程序运⾏中可能产⽣的异常。不过这往往要求应

⽤程序开发⼈员有⽐较丰富的⼯作经验以及由⽐较严密的思维逻辑。虽然这有⼀定的难度,但是笔者认为程序开发⼈员还是应

下溢异常), IndexOutOfBoundsException(出界异常), NullPointerException(空指针异常), EmptyStackException(空栈

异常), IllegalArgumentException(不合法的参数异常), NegativeArraySizeException, NoSuchElementException,

SecurityException, SystemException, UndeclaredThrowableException

1. interException

异常的解释是"程序遇上了空指针",简单地说就是调⽤了未经初始化的对象或者是不存在的对象,即把数组的初始化和数

组元素的初始化混淆起来了。数组的初始化是对数组分配需要的空间,⽽初始化后的数组,其中的元素并没有实例化,依然是

空的,所以还需要对每个元素都进⾏初始化(如果要调⽤的话)

2. otFoundException

异常的解释是"指定的类不存在"

3. eticException

这个异常的解释是"数学运算异常",⽐如程序中出现了除以零这样的运算就会出这样的异常。

4. ndexOutOfBoundsException

异常的解释是"数组下标越界",现在程序中⼤多都有对数组的操作,因此在调⽤数组的时候⼀定要认真检查,看⾃⼰调⽤

的下标是不是超出了数组的范围,⼀般来说,显⽰(即直接⽤常数当下标)调⽤不太容易出这样的错,但隐式(即⽤变量表⽰

下标)调⽤就经常出错了,还有⼀种情况,是程序中定义的数组的长度是通过某些特定⽅法决定的,不是事先声明的,这个时

候,最好先查看⼀下数组的length,以免出现这个异常。

5. lArgumentException

这个异常的解释是"⽅法的参数错误",⽐如or(int red,int green,int blue)这个⽅法中的三个值,如果有超过255

的也会出现这个异常,因此⼀旦发现这个异常,我们要做的,就是赶紧去检查⼀下⽅法调⽤中的参数传递是不是出现了错误。

6. lAccessException

这个异常的解释是"没有访问权限",当应⽤程序要调⽤⼀个类,但当前的⽅法即没有对该类的访问权限便会出现这个异

常。对程序中⽤了Package的情况下要注意这个异常

, 异常, Java

感谢阅读,希望能帮助到⼤家,谢谢⼤家对本站的⽀持!