目录
一、异常的基本概念
二 、为何需要异常处理
三 、异常的处理
四 、异常类的继承架构
五 、抛出异常
5.1、程序中抛出异常
5.2、指定方法抛出异常
六 、自定义异常
不管使用的那种语言进行程序设计,都会产生各种各样的错误。 Java 提供有强大的异常处理机制。在 Java 中,所有的异常封装到一个类中,程序出错时会将异常抛出。
即使在编译的时没有错误信息产生,但在程序运行时,经常会出现一些运行时异常,这种错误对 Java 而言是一种异常,有了异常就要有相应的处理方式。
一、异常的基本概念
异常也称为例外,是在程序运行过程中发生的、会打断程序正常执行的事件。
如下常见的异常:
1.1、算术异常(ArithmeticException)
1.2、空指针异常(NullPointException),没有给对象开辟内存空间,就去操作对象。
1.3、找不到文件异常(FileNotFoundException)
1.4、IO流异常(IOException)
Java 的异常处理机制也秉承着面向对象的基本思想。在 Java 中,所有的异常都是以类的类型存在。除了内置的异常之外, Java 也可以自定义异常类。此外, Java 的异常处理机制也允许自定义抛出异常。
二 、为何需要异常处理
异常是程序运行过程中发生的事件,比如除 0 溢出,数组越界、文件找不到等,这些事件的发生将阻止程序的正常运行。为了加强程序的健壮性,在程序设计时,必须考虑到可能发生的异常事件,并做出相应的处理。
Java 通过面向对象的方法来处理异常。在一个方法的运行过程中,如果发生了异常,则这个方法生成代表了该异常的一个对象,并把它交给了运行时系统,运行时系统寻找相应的代码来处理这个一异常。我们把生成异常对象并把它交个运行时系统的过程称为抛出一个异常。运行时系统在方法的调用栈中查找,从生成异常的方法开始进行追溯,直到找到包含相应异常处理的方法为止,这一过程称为捕获一个异常。
示例
public class Main {
public static void main(String[] args) {
int[] arr = new int[5];
System.out.println(arr[6]);
}
}
控制台显示
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 6 out of bounds for length 5
at com.demo.Main.main(Main.java:6)
三 、异常的处理
异常处理由 try、catch、finally等 3 个关键字所组成的程序块,语法格式:
public class Main {
public static void main(String[] args) {
try {
// 需要检查的程序语句
} catch (Exception e) {// Exception:异常类 e 对象名称
//异常发生时的处理语句
}finally {
// 一定会运行到的程序代码
}
}
}
try 程序块若是有异常发生,程序的运行便中断,并抛出 "异常类所产生的对象"。
抛出的对象如果属于 catch() 括号中内欲捕获的异常的类, catch 则会捕捉此异常,然后进到 catch 的块里继续运行。
无论 try 程序块是否捕捉到异常,或者捕捉到的异常是否与 catch() 括号里的异常相匹配,最后一定会运行 finally 块里的程序代码。
finally 的程序代码块运行结束后,程序再回到 try-catch-finally 块之后继续执行。
其实在异常捕捉的的过程做了两个判断:第 1 个是 try 程序块是否有异常产生,第 2 个是产生的异常是否和 catch() 括号内欲捕获的异常相匹配。
其中 finally 块是可以省略的,如果省略 finally 块不写,那么在 catch() 块运行结束后,程序将跳到 try-catch 块之后继续执行。
大致流程如下:
异常处理示例
public class Main {
public static void main(String[] args) {
int arr[] = new int[5];
try {// 异常检查代码块
arr[7] = 7; // 异常代码
} catch (ArrayIndexOutOfBoundsException e) {// 捕获异常代码块
System.out.println("数组越界异常");
}finally {// 异常一定执行代码块,这里一般资源关闭,例如io的关闭
System.out.println("一定执行的代码块");
}
System.out.println("执行main方法");
}
}
控制台显示
数组越界异常
一定执行的代码块
执行main方法
异常发生时,通常可以用两种方式来处理,一种交由 Java 默认的异常处理机制来处理,但这种处理方式, Java 通常只能输出异常信息,接着便终止程序的运行。
Java 默认的异常处理机制的显示如下图所示
另外一种方式是自行编写的 try-catch-finally 块来捕获异常。自行编写的程序代码来捕捉异常最大的好处是:可以灵活操控程序的流程,并且可以做出合适的处理。
异常处理机制选择流程:
四 、异常类的继承架构
异常类可以分两大类:java.lang.Exception 类与 java.lang.Error 类。这两个类均继承自 java.lang.Throwable 类。下图为 Throwable 类的继承关系图。
习惯上将 Error 与 Exception 类统称为异常类,但这两者本质上还是不同的。Error 类专门用来处理严重影响程序运行的错误,可是通常程序设计者不会设计程序代码去捕获这种错误,其原因在与即使捕捉到它,也无法给与适当的处理,如 java 虚拟机错误就是属于一种 Error。
不同于Error 类,Exception 类包含了一般性的异常,这些异常通常在 捕捉到之后便可做妥善的处理,以确保程序继续运行,如空指针异常、数组越界异常等就是属于这类异常。
从异常类的继承架构图中可以看出,Exception 类扩展出了数个子类,其中 IOException 和 RunntimeException 是比较常用的两种,RunntimeException 即使不编写异常处理的程序代码,依然可以编译成功,而这种异常必须是在程序运行才可有可能发生,例如数组的索引超出了范围(数组越界异常)。与 RunntimeException 不同的是,IOException 一定要编写异常处理的程序代码才行,它通常来处理输入/输出相关的操作,如文件的访问、网络的连接等。
五 、抛出异常
try-catch-finally 程序块的编写可以捕捉到异常,抛出异常需要用到 throw 关键字。抛出异常主要有两种方式(程序中抛出异常与指定方法抛出异常)。
5.1、程序中抛出异常
语法
throw 异常类示例对象
示例
public class Main {
public static void main(String[] args) {
int a = 1;
int b = 0;
try {
if(b==0){
throw new ArithmeticException("抛出一个算数异常");
}else {
System.out.println(a/b);
}
} catch (ArithmeticException e) {
System.out.println("抛出异常为"+e);
}
}
}
控制台显示
抛出异常为java.lang.ArithmeticException: 抛出一个算数异常
5.2、指定方法抛出异常
如果方法内的程序代码可能会发生异常,且方法内又没有使用任何的代码块来捕捉这些异常,则必须在声明方法时一并指明所有可能发生的异常,以便让调用此方法的程序得以做好准备来捕捉异常。也就是说,如果方法会抛出异常,则可将处理此异常的 try-catch-finally 块写在调用此方法的程序代码内。
如果要由方法抛出异常,则方法必须用下面的语法来声明。
方法名称(参数 ...) throws 异常1,异常2 .....
示例
public class Main {
void add(int a,int b) throws Exception{ //throws 声明抛出异常,调用者去处理异常
int c = a/b;
System.out.println(c);
}
public static void main(String[] args) {
Main main = new Main();
// 调用者处理异常
try {
main.add(4, 0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
六 、自定义异常
为了处理各种异常, Java 可通过继承的方式编写自己的异常类。因为所有可处理的异常均继承自 Exception 类,所以自定义的异常类也必须继承这个类。自定义异常语法如下:
class 异常名称 extends Exception {
}
自定义异常示例
public class DefaultException extends Exception {
public DefaultException() {
super();
}
public DefaultException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public DefaultException(String message, Throwable cause) {
super(message, cause);
}
public DefaultException(String message) {
super(message);
}
public DefaultException(Throwable cause) {
super(cause);
}
public static void main(String[] args) {
try {
throw new DefaultException("抛出自定义异常");
} catch (Exception e) {
System.out.println(e);
}
}
}
控制台显示
DefaultException: 抛出自定义异常
在 JDK 中提供的大量 API 方法之中含有大量的异常类,但这些类在实际开发中往往并不完全满足设计者对程序异常处理的需要,在这个时候就需要用自己去定义所需的异常类,用一个类清楚地写出所需要处理的异常。