异常
lkj 4/8/2022 JavaSE
# 理解异常
在 Java 语言中,将程序执行中发生不正常的情况统称为**「异常」**,注意⚠️:开发过程中的语法错误和逻辑错误不是异常
执行过程中所发生的异常事件可分为两大类
- Error:翻译过来就是**「错误」**。它是 java 虚拟机无法解决的严重问题,如:JVM 系统内部错误、内存资源耗尽等严重情况。比如:StackOverflowError(栈溢出)和 OutOfMemory 等。Error 是严重错误,会导致程序崩溃
- Exception:翻译过来是**「异常」**。它是其它错误或偶然的外在因素所导致的一般性问题,可以使用针对性代码进行处理,例如,空指针访问、视图读取不存在的文件、网络连接中断等。Exception 分为两大类:运行时异常(程序运行时发生的异常)和编译时异常(编程时,编译器检查出的异常)。其中运行时异常也称为
UncheckException
,编译时异常也称为CheckException
# 异常体系结构
# 异常处理方式
# try-catch-finally
一般结构
try{
// 将你觉得可能会发生异常的代码放置于此
}catch(Exception e){
// 当上述你放置的可能发生异常的代码真的发生异常时,会被程序捕获到,并将捕获到的错误封装成一个 Exception 对象
// 并且程序会进入该代码块继续执行,此时你可以拿到发生异常的信息(Exception e),然后继续你自己的业务逻辑
// 比如抛出该错误信息等
}finally{
// 该 finally 代码块无论有没有错误发生都会执行
// 通常将资源的释放代码放置于此
}
# throws
处理机制流程图如下
如果开发者没有显示地进行异常(运行时异常)的处理,程序会默认进行 throws Exception
异常的抛出,交给 JVM 进行处理,而 JVM 会直接输出信息并中断程序的执行,我们在控制台中看到的报错信息就是 JVM 输出的异常错误信息
# 异常举例
- 如果你觉得你的 try 代码块中可能会发生多个异常,则可以使用多个 catch 进行多次捕获,但是必须要将异常的子类放到前面,父类放到后面
try {
Person person = new Person();
person = null;
String name = person.getName(); // Nu llPointerException
System.out.println(name);
int n1 = 4;
int n2 = 0;
int res = n1 / n2; // ArithmeticException
System.out.println(res);
} catch (NullPointerException e){
}catch (ArithmeticException e){
}catch (Exception e) {
}
// 来看一个题目,m 方法的返回结果是多少
public static int m() {
int i = 1;
try {
i++; // 2
String[] names = new String[3];
if (names[1].equals("tom")) {// 此处抛出空指针异常
System.out.println(names[1]);
} else {
names[3] = "lkj";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e) {
return 2;
} catch (NullPointerException e) {// 捕获到异常
return ++i; // i = 3,底层会用一个临时变量将其保存 temp = 3;然后根据后续情况决定是否返回该临时变量
} finally { // finally 代码块中没有返回,则会将上述 catch 语句中的返回值进行返回
++i;// 4
System.out.println("i=" + i);
}
}
# 一些细节问题
- java 中的两大异常分为:编译时异常和运行时异常。对于运行时异常 java 会默认抛出异常,对于编译时异常 java 不作任何处理,也就是说需要你显示地进行异常的处理(要么是 throws 或 try-catch-finally)
- 在子类重写父类方法时,子类抛出的异常必须是父类抛出的异常的子异常或是父类抛出的异常