5 Java异常处理机制
5.1 概念
异常:Java程序运行期出现的错误
异常机制提供了程序退出的安全通道,当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器
5.2 分类
按运行时分类:
运行时异常(
RuntimeException)- 都是
RuntimeException类及其子类异常,如NullPointerException(空指针异常)等 - 这些异常是不可查异常,可以处理(抛出或捕获)也可以不处理
 - 通常是由于编程人员逻辑错误等原因引起,编码过程中程序员应尽量避免
 - 运行时异常将由Java运行时系统自动抛出,允许应用程序忽略运行时异常
 
- 都是
 非运行时异常(编译异常)
- 是
RuntimeException以外的异常,类型上属于Exception类及其子类,如IOException、SQLException等以及用户自定义的Exception异常 - 必须进行处理,如果不处理,程序就不能编译通过
 
- 是
 
按是否可查分类:
可查异常(
checked exceptions)- 编译器要求必须处理(抛出或捕获)的异常
 - 编译不通过时如果不处理会报错
 
不可查异常(
unchecked exceptions)- 编译器不要求强制处理的异常,出现错误需要修改相应程序,不需要抛出或捕获
 - 编译时不会报错
 - 包括运行时异常(
RuntimeException与其子类)和错误(Error) 
错误(
Error):- 是程序无法处理的错误,表示运行应用程序中较严重问题,大多数错误与代码编写者执行的操作无关
 - 例如:Java虚拟机运行错误(
Virtual MachineError)或当 JVM 内存资源使用完时会现OutOfMemoryError等 - 错误是不可查的,一般它们在应用程序的控制和处理能力之外
 
异常常用方法
e.printStackTrace():打印异常堆栈信息e.getMessage():获取异常信息,如果没有为nulle.getLocalizedMessage():一般由子类重写加入特定语言环境信息,默认与getMessage()相同
异常与重写
- 重写的方法必须和被重写的方法抛出的异常相同,或者不抛出,不能抛出被重写方法异常的父类或子类
 
5.3 异常的捕获和处理
5.3.1 抛出异常
- 使用
throw 异常类()抛出异常 - 使用
throws在方法上声明抛出的异常,可以是多个 - 异常抛出后并没有真正处理异常,需要调用方进行处理,如果调用方不能处理,则继续向上抛出
 
5.3.2 捕获异常
- 使用
try包裹可能出现异常的代码 - 使用
catch捕获对应的异常对象,可以有多个 finally中的代码不管有没有异常,最终都会被执行,finally可以省略catch到异常后,一定要做出处理,养成良好编程习惯,不要把异常吞掉catch多个异常时,注意顺序,应该先catch小类型,再父类型,如果是同级别的异常类,则不用注意顺序
5.3.3 代码示例
/*** 异常体系*/public class ExceptionSys {public static void main(String[] args) {// 常见异常commonExceptions();// 当调用异常的方法时,需要进行捕获或者继续抛出try {testThrow(1, 0);} catch (Exception e) {// e.printStackTrace();System.out.println(e.getMessage());System.out.println(e.getLocalizedMessage());}testTryCatch();}// 常见异常public static void commonExceptions() {// NullPointerException : 空指针异常byte[] bt = null;System.out.println(bt[1]);// ArrayIndexOutOfBoundsException : 数组下表越界异常byte[] btt = new byte[2];System.out.println(btt[3]);// ArithmeticException : 算数异常int a = 10, b = 0;int c = a/b;}// 抛出异常public static void testThrow(int a, int b) throws Exception {if (b == 0)throw new Exception(); // 也可以抛出确定的异常ArithmeticException或该异常的父类,如 throw new Exception();int c = a/b;System.out.println(c);}/** 注意抛出异常的顺序,父类放在最后,如果父类放在上面,会先进入父类,达不到想要的效果* 也可以不catch子类,直接catch父类异常*/public static void testTryCatch() {try {byte[] bt = null;System.out.println(bt[1]);byte[] btt = new byte[2];System.out.println(btt[3]);} catch (NullPointerException e){System.out.println("空指针异常");} catch (ArrayIndexOutOfBoundsException e){System.out.println("数组下标越界异常");} catch (Exception e){System.out.println("异常...");} finally {System.out.println("执行了finally");}}}
5.4 自定义异常
5.4.1 方法
继承一个异常父类
- 如果说自定义异常是编译期异常那么继承
Exception - 如果说自定义异常是运行期异常那么继承
RuntimeException - 或者根据情况继承其他
Exctption 
- 如果说自定义异常是编译期异常那么继承
 添加构造方法
- 可以传入异常参数信息,也可以不写参数
 
5.4.2 代码示例
/*** 自定义异常*/public class CustomException {public static void main(String[] args) {Bank bank = new Bank();try {bank.getMoney(100, 1000);} catch (NoMoneyException e) {e.printStackTrace(); // 打印异常堆栈信息System.out.println("异常信息:" + e.getMessage()); // 获取异常信息System.out.println(e.getLocalizedMessage()); // 一般由子类重写加入特定语言环境信息,默认与getMessage()相同// 其他相关处理...}}}class Bank {public void getMoney(double totalMoney, double getMoney) throws NoMoneyException {if (totalMoney < getMoney) {throw new NoMoneyException("余额不足...");} else {System.out.println("取款成功...");}}}// 自定义异常类class NoMoneyException extends Exception {// 自定义异常类中还可以进行其他操作,如传入一些相关参数,定义其他处理方法等public NoMoneyException(String msg) {super(msg); // 调用父类带参构造方法可以传入异常信息}}class Xbank extends Bank {/** 重写的方法必须和被重写的方法抛出的异常相同,或者不抛出* 不能抛出被重写方法异常的父类或子类*/@Overridepublic void getMoney(double totalMoney, double getMoney) throws NoMoneyException {// super.getMoney(totalMoney, getMoney);}}
