异常的处理
2022-06-04
异常的处理
分类
- 异常(Exception)
- 运行时异常RuntimeException(不受检异常):此类异常编译器不检查,一般是程序逻辑错误引起的,可捕获处理,也可不处理。如NullPointerException、ArrayIndexOutBoundException。
- 非运行时异常/编译时异常(受检异常):编译器检查此类异常,并且强制要做处理(捕获或抛出)。如IOException。
- 错误(Error):非代码性错误,与异常不同的是,这类错误是程序无法处理的。此类错误发生时,JVM将终止线程。如Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)。
异常的层次
Exception和Error都继承自Throwable类。层次图可见下图(列出主要的异常类)
常见内置异常类
Java 语言定义了一些异常类在 java.lang 标准包中。主要分类可见 https://www.runoob.com/java/java-exceptions.html#/
或者链接 https://blog.csdn.net/Pandafz1997/article/details/119898686#/ 给出的:
异常类 说明 ClassCastException 类型转换异常 ArrayIndexOutOfBoundsException 数组越界异常 NegativeArraySizeException 指定数组维数为负值异常 ArithmeticException 算数异常 InternalException Java系统内部异常 NullPointerException 空指针异常 IllegalAccessException 类定义不明确所产生的异常 IOException 一般情况下不能完成I/O操作产生的异常 EOFException 打开文件没有数据可以读取的异常 FileNotFoundException 在文件系统中找不到文件路径或文件名称时的异常 ClassNotFoundException 找不到类或接口所产生的异常 CloneNotSupportedException 使用对象的clone方法但无法执行Cloneable所产生的异常
异常处理
方法1:捕获处理
try+catch(+finally)
try {
xxx; //程序
} catch (ExceptionName e) {
xxx; //捕获异常时的处理
} finally {
xxx; //最终执行的代码块
}
若指定捕获特定的异常类,则在catch中指定异常类;若要捕获任意异常,则直接用Exception e
。
finally不是必须的,包含无论是否发生异常都会被执行到的代码块(一般包含清理类型等收尾善后性质的语句)。
有4种特殊情况,finally块不会被执行:
- finally语句块中发生了异常
- 前面的代码中执行了System.exit()退出程序
- 程序中所在的线程死亡
- 关闭CPU
需要注意的是,就算try块中有return,也会先执行完finally再return。
当try中抛出异常且catch中有return语句,finally中没有return语句,java先执行catch中非return语句,再执行finally语句,最后执行return语句。若try中没有抛出异常,则程序不会执行catch体里面的语句,java先执行try中非return语句,再执行finally语句,最后再执行try中的return语句。
但是:finally中有return时,会覆盖掉try和catch中的return。
如果finally中定义的数据是基本数据类型或文本字符串,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块中之前保存的值;如果finally中定义的数据是是引用类型,则finally中的语句会起作用,try中return语句的值就是在finally中改变后该属性的值。
以上举例见:https://blog.csdn.net/Pandafz1997/article/details/119898686#/
try不能单独存在,必须跟上catch或finally。
多重捕获
try {
xxx; //程序
} catch (ExceptionName1 e) {
xxx; //捕获异常1时的处理
} catch (ExceptionName2 e) {
xxx; //捕获异常2时的处理
}
执行逻辑:依次匹配异常,当匹配到该异常或尝试匹配完所有异常后,停止匹配。
通常,为捕获到所有可能出现的异常,可以在处理异常的末尾,加上Exception 类,这样即可以使所有异常都被捕捉到,也可以防止想捕获具体异常时被它提前捕获。
方法2:抛出异常
throw(用于抛出异常),throws(用在方法签名中,用于声明该方法可能抛出的异常)
public void fun() throws ExceptionName1, ExceptionName2 {
xxx; //可能抛出异常的代码块
}
若指定抛出特定的异常类,则在throws后面指定异常类;若要抛出任意异常,则直接用Exception
。可抛出多个异常类,用逗号隔开(如上)。
若要在执行代码块中手动抛出异常,格式为:throw new 异常类名(参数);
。通常用于抛出自定义的异常类。
public void fun() throws ArithmeticException {
throw new ArithmeticException("异常信息:除数不能为0");//抛出具体问题,编译时不检测
}
throw
在方法体中,程序会在throw语句后立即终止,它后面的语句执行不到(后面的语句写了也会编译不通过)。
try+catch(+finally) 和 throw 并不是互斥的,两者可以结合使用。例如:
try {
xxx;
throw new ExceptionName1("eMessage");
} catch ....
可以在finally语句块中有return语句,finally语句可以让throw和return共存。
注意:调用方法必须遵循一个原则:若覆盖一个方法,则不能声明与覆盖方法不同的异常,声明的任何异常必须是被覆盖方法所声明异常的同类或子类。如下例子(https://blog.csdn.net/Pandafz1997/article/details/119898686#/):
public class Example6_3 {
void method1() throws IOException {
}//合法
//编译错误,必须捕获或声明抛出IOException
void method2() {
method1();
}
//编译错误,必须捕获或声明抛出IOException或其父类
void method3() throws IOError {
method1();
}
//合法,声明抛出IOException
void method3() throws IOException {
method1();
}
//合法,声明抛出Exception,Exception是IOException的父类
void method4() throws Exception {
method1();
}
//合法,捕获IOException
void method5() {
try {
method1();
}catch (IOException e){
}
}
//编译错误,必须捕获或声明抛出Exception
void method6() {
try {
method1();
}catch (IOException e){
throw new Exception();
}
}
//合法,声明抛出Exception
void method7() throws Exception {
try {
method1();
}catch (IOException e){
throw new Exception();
}
}
}
常用方法
1 | public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
---|---|
2 | public Throwable getCause() 返回一个 Throwable 对象代表异常原因。 |
3 | public String toString() 返回此 Throwable 的简短描述。 |
4 | public void printStackTrace() 将此 Throwable 及其回溯打印到标准错误流。。 |
5 | public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
6 | public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |
自定义异常
Try-With-Resources
参考链接
https://blog.csdn.net/Pandafz1997/article/details/119898686#/