java基础-异常处理

2024-03-13

结构

Throwable  异常的根父类
    常用方法
            printStackTrace() 打印异常的详细信息
            getMessage() 获取发生异常的原因
Error  Throwable的子类
    java虚拟机无法解决的严重问题,jvm系统内部错误,资源耗尽等严重情况,一般不编写针对性的代码进行处理。例如StackOverflowError(栈内存溢出)OutMemoryError(java heap space)
Exception  Throwable的子类
    其他因编程错误或偶然的外在因素导致的一般性问题,需要编写针对性处理代码

Exception和RuntimeException区别

RuntimeException是运行时异常
	编译可以通过,在运行时可能抛出,出现概率高一些,一般针对于运行时异常,都不处理
Exception是一般异常
	编译不能通过,要求必须在编译之前,考虑异常的处理,不处理编译不通过


分类

编译时异常(checked异常、受检异常)
运行时异常(runtime异常、unchecked异常、非受检异常)

处理异常

方式1

// 捕获到异常之后,后面的代码可以继续执行
// 声明多个catch结构时,不同的异常类型不存在子父类关系情况下,声明顺序无所谓
// 不同的异常类型存在子父类关系情况下,必须将子类声明在父类结构的上面,否则将报错
// try中声明的变量,出了try结构之后,就不可以进行调用了
try {
    // 可能产生异常的代码
} catch (异常类型1 e) { // 依次匹配可能出现的异常,匹配到之后就不会继续匹配
} catch (异常类型2 e) {	

} finally { // 无法是否发生异常,都无条件执行的语句

}
System.out.println("继续执行其他代码");

finally说明

无法是否发生异常,无论try或catach中是否存在return语句等,finally中声明的代码都将执行
如果代码中执行了System.exit(0);finally中的代码将不会执行
开发中一些资源(输入流、输出流、数据库连接、socket连接等资源),在使用完后,必须显式关闭,否则GC不会自动回收这些资源,进而导致内存泄露;为了保证这些资源使用完后一定关闭,写在finally中
// 当finally中有return语句时,将返回finally中return的值
public Integer number(Integer num) {
	try {
		return num;
	} catch (NumberFormatException e) {
		return num--;
	} finally {
		System.out.println("结束");
		return ++num;
	}
}
number(10); // 11
// 如果finally中对返回值进行处理,代码中return的值是finally中处理前的值
public Integer number(Integer num) {
	try {
		return num;
	} catch (NumberFormatException e) {
		return num--;
	} finally {
		System.out.println("结束");
		++num;
	}
}
number(10);// 返回10
// 原因
    // 方法是一个栈针,栈针包含局部变量表、操作岀栈
    // num在局部变量表中
    // 操作岀栈也是一个栈
    // return的数据先临时放到操作岀栈中,return num;时已经将num=10放进操作岀栈中了
    // finally执行时操作的是局部变量表,finally执行后方法结束,操作岀栈中的num返回出去了

try结构可以直接包含finally,也可以包含catch和finally;但是finally不能单独使用

try {
} finally {
}
try {
} catch() {
}

方式2

在方法的声明处,使用"throws 异常类型1,异常类型2"

public void test() throws FileNotFoundException, IoException {

}

当有其他方法调用使用了throws的方法时,必须处理异常或继承抛出异常

public void test1() throws FileNotFoundException, IoException {
	test();
}
public void test2() {
	try {
		test();
	} catch (FileNotFoundException | IoException e) {

	}
}

两种方式使用场景

资源一定要被执行时,使用try-catch-finally
父类被重写方法没有throws异常类型,则子类重写方法中如果出现异常,只能考虑try-catch-finally
方法a一次调用了方法b,c,d等方法,方法b,c,d之间时递进关系,如果方法b,c,d中有异常,通常使用throws;而方法a中通常使用try-catch-finally

手动抛出异常

throw new 异常对象();

自定义异常

继承与现有的异常体系,通常继承于RuntimeException 或 Exception
通常提供几个重载的构造器
提供一个全局常量serialVersionUID,需要自定义一个值,不能与现有异常类的值相同,用于标识当前类

示例

public class MyException extends Exception {

	static final long serialVersionUID = 1L;
	public MyException() {

	}
	public MyException(String name) {
		super(name);
	}
	public MyException(String message, Throwable cause) {
		super(message, cause);
	}
}

为什么使用自定义异常

通过异常的名称就能直接判断此异常出现的原因。实际开发过程中,不满足我们指定的条件时,指明我们自己特有的异常类。


{/if}