Java异常机制
异常的定义
- 在使用计算机语言进行项目开发的时候,即使程序员把代码写的尽善尽美,程序在运行的时候难免会遇到各种突发状况,例如:
- 你写的某个模块,用户输入的数据格式不一定符合你的要求;
- 你的程序要打开某个文件,这个文件可能不存在或者格式不对;
- 你要读取数据库的数据时,数据可能是空的;
- 我们的程序跑着跑着,内存或者硬盘满了;
- 上述等问题都称为异常(Exception),程序报异常能让我们对自己写的程序进行合理的处理,防止程序崩溃。
- 异常发生在程序的运行过程中,影响程序的正常运行;
异常的分类
- 根据Java的异常处理,简单分为以下三类异常:
- 检查性异常:
- 编译器要求你必须处置的异常:你写的某段代码,编译器要求你必须要对这段代码try…catch,或者throws exception;
- 最具代表性的检查性异常就是用户错误操作引起的异常;
- 例如一个文件被用户删除了,然后要打开这个不存在的文件时,一个异常就发生了
- 这是程序员所无法预见的
- 运行时异常
- 编译器不要求强制处置的异常,与检查性异常相反;
- 程序员在写程序的时候出现的问题;例如:
- 除0错误:ArithmeticException;
- 数组下标越界:ArrayIndexOutOfBoundsException;
- 使用了空对象NullPointerException等等。
- 这是可以被程序员避免的异常
- 错误
- 错误其实不是异常,而是脱离程序员控制的问题。
- 例如当栈溢出了,一个错误就发生了
- 他们在编译的时候是检查不到的;
- 检查性异常:
异常体系结构
-
Java把异常当作对象来处理,并定义一个基类Java.lang.Throwable作为所有异常的超类。
-
在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。
Error类
-
Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关;
-
大多数是Java虚拟机运行错误(Virtual MachineError):
- 当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。
- 这些异常发生时,Java虚拟机(JVM)一般会选择线程终止
-
还有一种是发生在虚拟机试图执行应用时的错误,这些错误是不可查的,因为他们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。例如:
- 类定义错误(NoClassDefFoundError)
- 链接错误(LinkageError)
Exception类
- 在Exception分支中有一个重要的子类RuntimeException(运行时异常),这个类的异常会给我们编写的程序定义一些异常,例如:
- ArrayIndexOutOfBoundsException(数组下标越界异常)
- NullPointException(空指针异常)
- ArithmeticException(算数异常)
- MissingResourceException(丢失资源)
- ClassNotFoundException(找不到类)
- 这些异常都是程序里面已经写好的,不是检查异常,程序中可以选择捕获处理或者不处理。
- 发生这些异常一般与我们程序员有关,都是由程序逻辑错误引起,我们要尽量避免这些异常的发生;
Error和Exception的区别
- Error通常是灾难性的和致命的错误,这是程序无法控制和处理的;当出现这些错误时,Java虚拟机(JVM)一般会选择终止线程;
- Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
异常处理机制
- 异常处理机制一般就两种:
- 抛出异常
- 捕获异常
- 异常处理的五个关键字:
- try:监控区域
- catch:捕获异常
- finally:处理善后工作
- throw
- throws
捕获异常:快捷键Ctrl+Alt+T
-
我们通过try…catch…finally…去捕获异常
-
第一步try:
- 捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。
-
第二步catch:
- 如果发生异常,则尝试去匹配catch块,catch块可以有多个(因为try块可以出现多个不同类型异常);
- catch (Exceptiontype e):在catch语句块中是对异常对象进行处理的代码。
- 每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
- 每一个catch块用于捕获并处理一个特定的异常,或者这异常类型的子类。
- Java中也可以将多个异常声明在一个catch中。
- catch(Exception1 | Exception2 | Exception3 e)
- catch后面的括号定义了异常类型和异常参数。如果异常与之匹配且是最先匹配到的,则虚拟机将使用这个catch块来处理异常。
- 在catch块中可以使用这个块的异常参数来获取异常的相关信息。异常参数是这个catch块中的局部变量,其它块不能访问。与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。
- ①、getMessage() 获取异常信息,返回字符串。
- ②、printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
- 如果当前try块中发生的异常在后续的所有catch中都没捕获到,则先去执行finally,然后到这个函数的外部caller中去匹配异常处理器。
- 如果try中没有发生异常,则所有的catch块将被忽略。
- 注意:如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。例如:
- 可以用 ArithmeticException 类作为参数的地方,就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。
- 但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)。
-
第三步finally:
- 如果执行完try不管有没有发生异常,则接着去执行finally块和finally后面的代码(如果有的话)。
- finally块通常是可选的,不是一定要写的。
- 捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。
- 不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行。
- 一个try至少要有一个catch块,否则, 至少要有1个finally块。但是finally不是用来处理异常的&#x