• 这种在运行时出现的意外错误称为“异常”
• 对异常的处理机制也成为判断一种语言是否成熟的标准。
• 好的异常处理机制会使程序员更容易写出健壮的代码,防止代码中Bug的蔓
延
Java中的异常类可以分为两种:
• 错误(Error):一般指与虚拟机相关的问题,如系统崩溃、虚拟机错误、
动态链接失败等,这些错误无法恢复或捕获,将导致应用程序中断;
• 异常(Exception):因程序编码错误或外在因素导致的问题,这些问题能
够被系统捕获并进行处理,从而避免应用程序非正常中断,例如:除以0、
对负数开平方根、空指针访问等。
Throwable是所有异常类的父类,Error和Exception都继承此类:
当程序产生Error时,因系统无法捕获Error并处理,程序员将无能为力,
程序只能中断;
当发生Exception时,系统可以捕获并做出处理,因此本章所介绍的异常处
理操作都是针对Exception及其子类而言的。
Exception异常从编程角度又可以分为以下两种类型:
非检查型异常:编译器不要求强制处置的异常,该异常是因编码或设计不当导致的,这种异常可以避免,RuntimeException及其所有子类都属于非检查型异常。
检查型异常:编译器要求及其子类(RuntimeException及其子类除外)都属于检查型异常必须处理的异常,该异常是程序运行时因外界因素而导致的,Exception。
非检查型异常:
类名 说明
ArrayIndexOutOfBoundsException 数组下标越界异常
NullPointerException 空指针访问异常
NumberFormatException 数字格式化异常
ArithmeticException 算术异常,如除以0溢出
ClassCastException 类型转换不匹配异常
检查型异常:
SQLException 数据库访问异常
IOException 文件操作异常
FileNotFoundException 文件不存在异常
ClassNotFoundException 类没找到异常
• 检查型异常体现了Java语言的严谨性,程序员必须对该类型的异常进行处理,否则程序编译不通过,无法运行。RuntimeException及其子类都是Exception的子类,Exception是所有能够处理的异常的父类。
• 异常是在程序执行期间产生的,会中断正常的指令流,使程序不能正常执行下去 。
• 为了使程序出现异常时也能正常运行下去,需要对异常进行相关的处理操
作,这种操作称之为“异常处理”。
• Java的异常处理机制可以让程序具有良好的容错性,当程序运行过程中出
现意外情况发生时,系统会自动生成一个异常对象来通知程序,程序再根据
异常对象的类型进行相应的处理。
Java提供的异常处理机制有两种:
• 使用try…catch捕获异常:将可能产生异常的代码放在try语句中进行隔离,如果遇到异常,程序会停止执行try块的代码,跳到catch块中进行处理。
• 使用throws声明抛出异常:当前方法不知道如何处理所出现的异常,该异
常应由上一级调用者进行处理,可在定义该方法时使用throws声明抛出异常。
Java中捕获异常并处理的语句有以下几种:
• try…catch语句
• try…catch…finally语句
• 自动关闭资源的try语句
• 嵌套的try…catch语句
• 多异常捕获
try…catch语句:
(1) 单catch处理语句
• 单catch处理语句只有一个catch,是最简单的捕获异常处理语句:
try {
// 产生除以0的算术异常
int i = 10 / 0;
System.out.println("i的值为:" + i);
} catch (Exception e) {
// 输出异常信息
e.printStackTrace();
}
// 该条语句继续执行
System.out.println("end");
• 所有异常对象都包含以下几个常用方法用于访问异常信息:
• getMessage()方法:返回该异常的详细描述字符串;
• printStackTrace()方法:将该异常的跟踪栈信息输出到标准错误输出;
• printStackTrace(PrintStream s)方法:将该异常的跟踪栈信息输出到指
定输出流;
• getStackTrace()方法:返回该异常的跟踪栈信息。
(2)多catch处理语句
代码1:
Scanner scanner = new Scanner(System.in);
int array[] = new int[3];
try {
System.out.println("请输入第1个数:");
String str = scanner.next(); // 从键盘获取一个字符串
// 将不是整数数字的字符串转换成整数,会引发NumberFormatException
int n1 = Integer.parseInt(str);
System.out.println("请输入第2个数:");
int n2 = scanner.nextInt(); // 从键盘获取一个整数
// 两个数相除,如果n2是0,会引发ArithmeticException
array[1] = n1 / n2;
// 给a[3]赋值,数组下标越界,引发ArrayIndexOutOfBoundsException
array[3] = n1 * n2;
System.out.println("两个数的和是" + (n1 + n2));
}
代码2:
catch (NumberFormatException ex) {
System.out.println("数字格式化异常!");
} catch (ArithmeticException ex) {
System.out.println("算术异常!");
} catch (ArrayIndexOutOfBoundsException ex) {
System.out.println("下标越界异常!");
} catch (Exception ex) {
System.out.println("其他未知异常!");
}
System.out.println("程序结束!");
try…catch…finally语句:
• 在Java异常处理机制中,提供了finally块,可以将回收代码放入此块中,
不管try块中的代码是否出现异常,也不管哪一个catch块被执行,甚至在try块或catch块中执行了return语句,finally块都会被执行。
• Java垃圾回收机制不会回收任何物理资源,垃圾回收机制只能回收堆内存中对象所占用的内存。在Java程序中,通常使用finally回收物理资源。
FileInputStream fis = null;
try {
// 创建一个文件输入流,读指定的文件
fis = new FileInputStream("zkl.txt");
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
// return语句强制方法返回
return; //(1)
// 使用exit来退出应用
// System.exit(0); // (2)
}
finally {
// 关闭磁盘文件,回收资源
if (fis != null) {
try {
fis.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
System.out.println("执行finally块里的资源 • 回收!");
}
自动关闭资源的try语句:
• 从Java 7开始,增强了try语句的功能,允许在try关键字后紧跟一对小括
号,在小括号中可以声明、初始化一个或多个资源,当try语句执行结束时会自动关闭这些资源。
public static void main(String[] args) {
// 自动关闭资源的try语句,JDK 7.0以上才支持
try (FileInputStream fis = new FileInputStream("zkl.txt")) {
// 对文件的操作...
} catch (IOException ioe){
System.out.println(ioe.getMessage());
}
// 包含了隐式的finally块,fis.close()关闭资源
}
嵌套的try…catch语句:
try {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入第1个数:");
// 从键盘获取一个字符串
String str = scanner.next();
// 将不是整数数字的字符串转换成整数,
//会引发NumberFormatException
int n1 = Integer.parseInt(str);
try {
FileInputStream fis = new FileInputStream("zkl.txt"); } catch (IOException ioe){
System.out.println(ioe.getMessage());
}
System.out.println("请输入第2个数:");
// 从键盘获取一个整数
int n2 = scanner.nextInt();
System.out.println("您输入的两个数的商是:" + n1 / n2);
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("程序结束!");
• 嵌套的try…catch语句可以嵌套多层,这方面没有明确的限制,但通常没有必要使用超过两层的嵌套异常处理。层次太深的嵌套异常处理会降低程序的可读性,而且也没有太大的必要,完全可以使用其他方式实现。
多异常捕获:
• 从Java 7开始,一个catch块可以捕获多种类型的异常
其中:
• 捕获多种类型的异常时,多种异常类型之间使用竖杠“|”进行间隔;
• 多异常捕获时,异常变量默认是常量,因此程序不能对该异常变量重新赋值。
语法:
try {
//业务实现代码(可能发生异常)
......
}catch (异常类A [|异常类B ...|异常类N] 异常对象) {
//多异常捕获处理代码
}
...... //可以有多个catch语句
抛出异常:
• Java中抛出异常可以使用throw或throws关键字:
• 使用throw抛出一个异常对象:当程序出现异常时,系统会自动抛出异常,
除此之外,Java也允许程序使用代码自行抛出异常,自行抛出异常使用
throw语句完成;
• 使用throws声明抛出一个异常序列:throws只能在定义方法时使用。当定
义的方法不知道如何处理所出现的异常,而该异常应由上一级调用者进行处
理,可在定义该方法时使用throws声明抛出异常。
throw抛出异常对象:
• throw语句抛出的不是异常类,而是一个异常实例对象,并且每次只能抛出
一个异常实例对象
语法:
throw 异常对象
throws声明抛出异常序列:
语法:
[访问符] <返回类型> 方法名([参数列表]) throws异常类A [,异常类B… ,异常类N]{ //方法体 }
• 自定义异常类都继承Exception或RuntimeException类
public class AgeException extends Exception {
public AgeException() {......}
public AgeException(String msg) {
super(msg);
}
}