Java异常处理详解(No.13)
1、异常定义(Exception Definition)
异常(英文:Exception,中文:例外)是指程序运行过程中出现的不期而至的各种状况,如:“非法参数、数据库表中某一字段数据为空、内存溢出、文件找不到或格式不对、网络连接失败、磁盘空间已满”等。
异常发生在程序运行期间,其严重影响了正常的程序执行流程。
2、异常分类(Exception Classification)
2.1、检查性异常(Check Exception)
最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。如:用户打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单的忽略。
2.2、运行时异常(Runtime Exception)
运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
2.3、错误(Error)
错误不是异常,而是脱离程序控制的问题。错误在代码中通常被忽略,如:当栈溢出时,一个错误就发生了,其在编译时是无法检查到的。
3、异常体系结构(Exception Architecture)
Java把异常当作对象来处理,并定义了一个基类"java.lang.Throwable"作为所有异常类的超类。
在Java的API中已经定义了许多异常类,这些异常类分为两大类(即,错误[Error]类与异常[Exception]类)。
Java异常体系结构,如下图所示。
4、Error类(Error Class)
- 4.1、Error类对象由Java虚拟机(Java Virtual Machine,JVM)生成并抛出,大多数错误与代码编写者所执行的操作无关。
- 4.2、Java虚拟机运行错误(VirtualMachineError),当JVM不再有继续执行操作所需的内存资源时,将出现异常“OutOfMemoryError”,这些异常发生时,Java虚拟机一般会选择将线程终止。
- 4.3、还有异常发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError),这些错误是不可查的,因为其在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
5、Exception类(Exception Class)
-
5.1、在Exception分支中有一个重要的子类RuntimeException(运行时异常)。
这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。其常见异常如下所示。
- 5.1.1、ArithmeticException(算术异常)。
- 5.1.2、ArrayIndexOutOfBoundsException(数组下标越界异常)。
- 5.1.3、IllegalArgumentException(非法参数异常)。
- 5.1.4、NullPointerException(空指针异常)。
- 5.1.5、ClassNotFoundException(未找到类异常)。
- 5.1.6、MissingResourceException(丢失资源异常)。
- 5.1.7、UnkownTypeException(未知类型异常)。
-
5.2、这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
6、Error与Exception区别(The Difference Between Error And Exception)
- 6.1、Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(Java Virtual Machine,JVM)一般会选择终止线程。
- 6.2、Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
7、异常处理机制(Exception Handling Mechanism)
异常处理5个关键字:“try、catch、finally、throw、throws”。
7.1、捕获异常(Catch Exception)
7.1.1、示例代码(Sample Code)
其示例,如以下代码所示。
package com.xueshanxuehai.exception;
public class CatchException {
public static void main(String[] args) {
int a=1;
int b=0;
try {//try:监控区域
System.out.println(a/b);
}catch (ArithmeticException e){//catch(想要捕获的异常类型):捕获异常
System.out.println("ArithmeticException");
}catch(RuntimeException e){
System.out.println("RuntimeException");
}catch(Exception e){
System.out.println("Exception");
}catch(Throwable e){
System.out.println("Throwable");
}finally {//finally:处理善后工作
System.out.println("Finally");
}
// //生成“try...catch...finally代码块“快捷键”Ctrl+Alt+T“,然后选择”try / catch / finally“选项即可自动生成
// try {//try:监控区域
// System.out.println(a/b);
// } catch (Exception e) {//catch(想要捕获的异常类型):捕获异常
// e.printStackTrace();//打印错误的栈信息
// } finally {//finally:处理善后工作
// }
}
}
7.1.2、运行结果(Run Result)
其运行结果,如下图所示。
7.1.3、注意事项(Matters Needing Attention)
- 7.1.3.1、捕获异常时,一定要使用“try{…}catch(…){…}”语句,可以不使用“finally{…}”语句。
- 7.1.3.2、一般使用“finally{…}”语句时,主要用于对象使用完后关闭并释放内存,如:Scanner、IO等对象。
- 7.1.3.3、“try{…}”语句中代码块为“捕获异常时的监控区域”,“catch(…){…}”语句中代码块为“捕获异常后的处理异常区域”,“finally{…}”语句中代码块为“无论有无捕获异常都会执行的处理善后工作区域”。
- 7.1.3.4、如果当前程序需要同时捕获多个异常情形时,这时必须按照异常类型从小到大的顺序去捕获异常,如:“ArithmeticException<RuntimeException<Exception<Throwable”。
7.2、抛出异常(Throw Exception)
7.2.1、使用throw在方法中抛出异常(Use Throw To Throw Exception In The Method)
其示例,如以下代码所示。
package com.xueshanxuehai.exception;
public class ThrowException {
public static void main(String[] args) {
try {//try:监控区域
new ThrowException().division(1, 0);//使用”throw“主动抛出异常
} catch (Exception e) {//catch(想要捕获的异常类型):捕获异常
e.printStackTrace();//打印错误的栈信息
} finally {//finally:处理善后工作
System.out.println("ThrowException->Finally");
}
}
public void division(int a, int b) {
if (b == 0) {
throw new ArithmeticException();//throw:主动抛出此异常,一般在方法中使用
}
}
}
其运行结果,如下图所示。
7.2.2、使用throws在方法上抛出异常(Use Throws To Throw Exception On The Method)
其示例,如以下代码所示。
package com.xueshanxuehai.exception;
public class ThrowsException {
public static void main(String[] args) {
try {//try:监控区域
new ThrowsException().division(1, 0);//使用”throws“主动抛出异常
} catch (Exception e) {//catch(想要捕获的异常类型):捕获异常
e.printStackTrace();//打印错误的栈信息
} finally {//finally:处理善后工作
System.out.println("ThrowsException->Finally");
}
}
public void division(int a, int b) throws ArithmeticException {//throws:若方法中无法处理此异常,则从方法上主动抛出此异常
System.out.println(a / b);
}
}
其运行结果,如下图所示。
7.2.3、注意事项(Matters Needing Attention)
- 7.2.3.1、一般使用“throw”在方法中主动抛出异常。
- 7.2.3.2、若方法中无法处理异常,则使用“throws”从方法上主动抛出异常。
8、自定义异常(Custom Exception)
使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。
用户自定义异常类,只需要继承“Exception”类即可。
8.1、操作步骤(Operation Steps)
- 8.1.1、创建自定义异常类。
- 8.1.2、在方法中通过throw关键字抛出异常对象。
- 8.1.3、如果在当前抛出异常的方法中处理异常,可以使用“try-catch”语句块捕获并处理异常;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
- 8.1.4、在出现异常方法的调用者中使用“try-catch”语句块捕获并处理异常。
8.2、示例代码(Sample Code)
CustomException类,如以下代码所示。
package com.xueshanxuehai.exception;
//自定义异常类
public class CustomException extends Exception {
//传递数字<0时需抛出自定义异常信息
private int detail;
//有参构造方法
public CustomException(int detail) {
this.detail = detail;
}
//重写toString方法
@Override
public String toString() {//toString:异常的打印信息
return "CustomException{" +
"detail=" + detail +
'}';
}
}
CallCustomException类,如以下代码所示。
package com.xueshanxuehai.exception;
public class CallCustomException {
//可能会存在异常的方法
static void callCustomException(int detail) throws CustomException {
System.out.println("传递的参数为:" + detail);
if (detail < 0) {
throw new CustomException(detail);//抛出异常
}
System.out.println("End");
}
public static void main(String[] args) {
try {
callCustomException(-1);
} catch (CustomException e) {
System.out.println("CallCustomException->" + e);//自定义处理异常的代码
// e.printStackTrace();//打印错误的栈信息
}
}
}
8.3、运行结果(Run Result)
其运行结果,如下图所示。
9、实际应用经验总结(Summary Of Practical Application Experience)
- 9.1、处理运行时异常时,采用逻辑去合理规避,同时辅助“try-catch”处理。
- 9.2、在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常。
- 9.3、对于不确定的代码,也可以加上“try-catch”来处理潜在的异常。
- 9.4、尽量去处理异常,切忌只是简单的调用“printStackTrace()”方法去打印输出。
- 9.5、具体如何处理异常,要根据不同的业务需求和异常类型去决定。
- 9.6、尽量添加"finally"语句块去释放占用的内存资源。