1 异常
1.1 异常的概念
-
异常概念: 异常是程序在运行时出现的不正常情况.
异常产生后没有正确的处理, 出导致程序的中断 , 造成损失, 开发中我们要考虑到各种可能发生的异常, 对其作出正确的处理, 保证程序正常执行.
1.2 异常的继承体系
- Throwable类: 包含2个子类Error( 错误 )和Exception( 异常 ).
1.3 Error
- Error: 代码运行时在JVM出现问题. 我们需要修改代码来解决该错误.
常见的Error:
-
StackOverflowError: 当应用程序递归太深而发生堆栈溢出时, 抛出该错误. 比如死循环或者没有出口的递归调用.
-
OutOfMemoryError: 因为内存溢出或没有可用的内存提供给垃圾回收器时, Java 虚拟机无法分配一个对象, 这时抛出该错误. 比如new了非常庞大数量的对象而没释放.
1.4 Exception
- Exception: 表示程序运行时出现的不正常的情况, 一般大多数都是表示轻度到中度的问题, 属于可预测, 可恢复的问题. 我们需要通过合理的异常处理, 让程序正常的运行直到程序完成.
常见的Exception:
- ArrayIndexOutOfBoundsException: 用非法索引访问数组时抛出的异常. 如果索引为负或大于等于数组大小, 则该索引为非法索引. int[] arr = new int[ 10 ]; arr[10];就异常
- ArithmeticException: 当出现异常的运算条件时,抛出此异常. 例如: 一个整数“除以零”时, 抛出此类的一个实例.
- NullPointerException: 当应用程序试图在需要对象的地方使用 null 时, 抛出该异常. 这种情况包括:
- 调用 null 对象的实例方法.
- 访问或修改 null 对象的字段.
- 将 null 作为一个数组, 获得其长度等.
- NumberFormatException: 数字格式化异常.比如: Integer.parseInt(“123aa”);
2 捕获异常
- 异常一旦出现, 程序会立即终止, 在开发中我们一定要处理异常, 处理异常的两种方法:
- 直接处理异常( 捕获异常 ).
- 自身抛出异常, 不处理.
2.1 单个异常的捕获
处理异常的语法格式:
try{
//可能会有异常的代码
}catch(要捕获的异常类型 变量){
//处理异常的代码
}
public class TryCatchDemo {
public static void main(String[] args) {
System.out.println("开始");
//divide方法虽然出错,但是已经异常处理,不会影响到调用方法继续向下执行
divide(2, 0);
//能够执行到结束
System.out.println("结束");
}
public static void divide(int a, int b) {
try {
//可能会出现异常的代码
System.out.println(a / b);
//捕获到ArithmeticException异常
} catch (ArithmeticException e) {
//输出异常
System.out.println("除法运算有错误");
}
}
}
当然也可以使用Exception和Throwable接受所有的异常对象( 多态 ).但是不建议使用Throwable,因为Throwable有Error和Exception, Error是没有必要处理的.
2.2 访问异常信息
- String getMessage(): 返回异常信息.
- void printStackTrace( ): 打印异常类型名和异常信息, 在程序中异常的位置.
public class TryCatchDemo {
public static void main(String[] args) {
System.out.println("开始");
//divide方法虽然出错,但是已经异常处理,不会影响到调用方法继续向下执行
divide(2, 0);
//能够执行到结束
System.out.println("结束");
}
public static void divide(int a, int b) {
/* try {
可能会出现异常的代码
}catch (可能出现异常的类型 变量){
//处理异常
//获取到异常对象中封装的异常信息
}*/
try {
//可能会出现异常的代码
System.out.println(a / b);
//捕获到ArithmeticException异常
} catch (ArithmeticException e) {
//输出异常
System.out.println("除法运算有错误");
//异常的信息
System.out.println(e.getMessage());
//打印异常类型名和异常信息, 在程序中异常的位置.
e.printStackTrace();
}
}
}
2.3 捕获多个异常
- 多个异常: 程序中存在多种异常.
捕获多个异常语法:
try{
//可能会有异常的代码
}catch(要捕获的异常类型A 变量){
//处理异常的代码
}catch(要捕获的异常类型B 变量){
//处理异常的代码
...
}catch(要捕获的异常类型N 变量){
//处理异常的代码
}
public class TryCatchCatchDemo {
public static void main(String[] args) {
divide("5", "a");
}
public static void divide(String a, String b) {
try {
//下面代码可能会出现两种异常
//ArithmeticException
//NumberFormatException
int x = Integer.parseInt(a);
int y = Integer.parseInt(b);
System.out.println(x / y);
//处理数字格式化异常
} catch (NumberFormatException e) {
System.out.println("数字格式化异常");
e.printStackTrace();
//处理算术异常
} catch (ArithmeticException e) {
System.out.println("算术异常");
e.printStackTrace();
//处理其他异常
//父类异常不能放在第一个, 不然子类异常不管怎么样都访问不到了
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.4 finally
- finally语法格式:
try{
//可能会有异常的代码
}catch(要捕获的异常类型 变量){
//处理异常的代码
}finally{
//前面无论有没有异常,这里都执行
}
try语句块必须和catch语句块或try和finally同在, 不能单独存在try或catch或finally.
finally块总会执行, 不论是否有错误出现. 但如果try语句块中或catch语句块存在JVM退出代码( System.exit(0); ) , finally块就不会被执行了. 一般, 我们把关闭资源的代码放在finally里面, 保证资源总是能关闭.
public class TryCatchFinallyDemo {
public static void main(String[] args) {
divide("5", "0");
System.out.println("结束");
}
public static void divide(String a, String b) {
try {
//下面代码可能会出现两种异常
//ArithmeticException
//NumberFormatException
int x = Integer.parseInt(a);
int y = Integer.parseInt(b);
System.out.println(x / y);
//处理数字格式化异常
} catch (NumberFormatException e) {
System.out.println("数字格式化异常");
//System.exit(0);
e.printStackTrace();
//处理算术异常
} catch (ArithmeticException e) {
System.out.println("算术异常");
e.printStackTrace();
//System.exit(0);
//try和catch中没有关闭资源代码(System.exit(0);)
//finally中的语句无论怎么样都要执行
} finally {
System.out.println("finally");
}
}
}
3 抛出异常
-
抛出异常: 自身抛出异常, 不处理, 而抛出异常, 有两种:
-
方法里面会出现异常, 但方法不想处理这个异常, 使用throw抛出异常对象.
-
方法里面可能会产生异常, 自身不想处理, 提醒调用该方法的方法做需要处理, 使用throws关键字.
-
3.1 throws关键字
- throws: 在可能出现异常的方法上声明提醒可能会出现异常的类型.
throw语法格式:
修饰符 返回值类型 方法名(参数列表...) throws 异常A, 异常B..{
}
public class ThrowsDemo {
public static void main(String[] args) {
//如果调用的方法可能存在异常, 那我们应该选择处理或者抛出
try {
divide(3, 1);
divide(3, 0);
} catch (Exception e) {
e.printStackTrace();
}
}
//在方法声明上告知调用者, 这里可能存在Exception异常
public static void divide(int a, int b)throws Exception {
System.out.println(a / b);
}
}
3.2 throw关键字
- throw: 当方法内, 需要返回一个错误结果给调用者时, 一般使用throw关键字在方法内手动抛出一个具体的异常对象.
public class ThrowDemo {
public static void main(String[] args) {
try {
isExist("");
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
//检查用户名是否存在
public static void isExist(String name) throws Exception {
//通过一个数组模拟现在已经存在的用户名
String[] n = {"LL", "ll"};
if (name != null && name.length() > 0) {
for (String n1 : n) {
if (name.equals(n1)) {
//用抛异常的方式,告知调用者,这里存在问题
throw new Exception("对不起,用户名" + name + "已经存在");
} else {
System.out.println("注册成功");
}
}
}
throw new Exception("用户名为空");
}
}
3.3 throws和throw的区别
throws: 用于方法声明上, 表示该方法不需要处理某种类型异常,也在提醒该方法调用者需要处理异常.
throw: 用于返回一个错误结果, 抛出具体异常类的对象给调用者.
4 异常分类
- 异常分类: 编译异常和运行异常.
- RuntimeException和其子类属于运行异常, 其他都是编译异常.
4.1 运行异常
- 运行异常: 在编译时期不被检测, 只有在运行时期才会被检查出来.
可以不使用try-catch和throws处理运行异常.
4.2 编译异常
- 编译异常: 又称检查异常, 在编译时期就会被检测到的异常. 必须处理编译异常, 使用try-catch或throws处理.
4.3 自定义异常类
- 自定义异常类: 一个异常类只表示某种特定的异常类型.
- 自定义异常的两种方式: 可以继承Exception类或RuntimeException类. 一般推荐继承RuntimeException类.
- 继承异常后: 我们需要提供无参构造和一个String类型参数构造器.
5 总结
5.1 什么是异常? 程序员为什么需要处理异常?
异常: 程序运行时出现的不正常情况.
为什么需要处理异常: 如果异常没有正确的处理, 或导致程序的中断.
5.2 Java的异常继承体系是什么?
Throwable->Error,Exception.
Exception->Exception, RuntimeException.
5.3 说说Throwable、Error、Exception的区别
Throwable: Error和Exception的父类,用来存储异常信息.
Error: 表示代码运行时JVM出现的错误, 一般用该代码来解决该问题.
Exception: 表示程序运行时的异常, 也就是一些不正常的情况, 需要我们通过合理的异常处理, 让程序正常.
5.4 说说异常的分类和区别
异常的分类: 捕获异常和抛出异常.
区别: 捕获异常是直接处理异常, 抛出异常是自身抛出异常不进行处理.
5.5 捕获异常是什么意思? 语法是什么?
捕获异常: 直接处理异常.
语法: try{
//可能出现异常的代码
}catch(要捕捉的异常类型 变量){
//处理捕获到的异常的代码
}
5.6 finally语句块的特点是什么?
try{
//可能出现异常的代码
}catch(要捕捉的异常类型 变量){
//处理捕获到的异常的代码
}finally{
//无论是不是有异常,最后都会执行代码
}
5.7 什么时候需要抛出异常? 语法是什么?
方法里面会出现异常, 但方法不想处理异常, 提醒调用该方法的人需要处理.
修饰符 返回值类型 方法名(参数列表…) throws 异常A, 异常B…{
}
5.8 说说throw和throws的区别
throw: 用于返回一个错误结果, 抛出具体异常类的对象给调用者.
throws: 用于方法声明的时候, 不想处理异常然后抛出异常, 提醒调用者需要处理异常.
5.9 自定义异常时需要注意哪些问题?
- 自定义异常可以继承Exception类和RuntimeException类. 一般推荐继承RuntimException.
- 继承以后, 一般需要提供一个无参构造器和一个带String类型参数的构造器.