异常Exception

【疑点】

带有finally的语句执行顺序

1.异常概述

异常是程序运行中的特殊情况
1.1 Throwable类
Throwable是Java中所有异常和错误的基类,位于java.lang包下
--| Error 错误:硬件异常,虚拟机异常,执行逻辑错误
--| Exception 异常:程序在执行期间或配置中发生错误,可处理

构造方法:
	Throwable();
		创建一个Throwable类对象,其中保存的异常或者错误信息为null
	Throwable(String message); 【重点】
		创建一个Throwable类对象,其中保存的异常或者错误信息为message

成员方法:	
	String toString();
		得到当前异常的简要信息描述
	String getMessage();
		获取当前Throwable类对象中保存的异常或者错误信息
	void printStackTrace();	【伪重点】
    	在命令行中展示错误的前因后果!!!红色字体
1.2 Error和Exception
Error 错误
	无法处理,只能避免!!!
	错误都是Error结尾
Exception 异常
	可以处理,还有挽回的余地
	异常都是Exception结尾
【举例】	
Java代码中有一个数组需要申请64GB内存,(目前电脑内存32GB)
	不可能!!!错误 Error

Java中代码需要一个数组,但是给予的操作不合法
	可以处理的,Exception
Exception
--| RuntimeException(非检测异常):运行期异常,可处理可不处理,可通过编译
--| CheckException(受查异常,检测异常):必须处理,不处理不能编译

1. 异常处理

1.1 Exception的两种处理方式概述
小门诊
	手指划伤,需要包扎处理,当场处理好
	发烧去小门诊,不敢接,要不您去指定发烧医院

当场处理好,拒之门外。
	这两种方式就是Java中处理异常的方式
	【捕获】 有能力处理你就捕获,自己的问题你就捕获
	【抛出】 没有办法处理,或者不是自己的问题,和自己无关,因别人导致的错误,抛出
1.2 捕获异常
1.2.1 基本格式
格式:
	try {
		// 有可能出现问题的代码,存在一定隐患的代码
	} catch (异常类型) {
		// 对应当前异常类型的处理方式
		// 【因为技术所限,我们只能sout 或者 printStackTrace 后期我们会使用日志log】
	}
public class Demo1 {
	public static void main(String[] args) {
		int num1 = 0;
		int num2 = 20;
		
		int ret = 0;
		
		/*
		 * num2 / num1 是存在一定的隐患的,如果num1保存的数据是0,
		 * 这里会出现一个算术异常
		 */
		try {
			// 有可能出现异常的代码
			ret = num2 / num1;
		} catch (ArithmeticException e) {
			/*
			 * ArithmeticException 算术异常,catch块中捕获对应异常
			 * catch大括号内是对应的处理方式,现在只能展示效果
			 */
			e.printStackTrace();
		}
		
		System.out.println(ret);
		
		/*
		 * java.lang.ArithmeticException: / by zero
		 * 			at com.qfedu.a_exception.Demo1.main(Demo1.java:16)
		 * 0
		 */
	}
}
1.2.2 细节问题和注意事项
1. 代码中出现异常,JVM会终止代码运行,如果使用try catch捕获处理异常,JVM会认为当前代码中不存在异常,可以继续运行。
	【类比】球员受伤,下场处理,处理完毕,回到场上

2. 在try大括号内或者catch大括号内都是局部变量,处理操作数据时小心谨慎。

3. try - catch捕获处理异常,可以处理多种异常情况!!!而且建议异常处理分门别类,对症下药

4. 代码中存在多种隐患,存在多个异常情况,try - catch捕获有且只能处理第一个出现异常的代码,因为JVM从异常代码开始直接进入异常捕获阶段

5. Exception作为Java中所有异常的超类,在捕获异常处理时如果直接使用Exception进行捕获处理,无法做到异常对症下药操作。

6. Exception可以作为try - catch 最后一个,用于处理其他异常捕获之后没有对症方式遗留问题。[不多见]

7. 多个异常时,无继承关系的异常没有上下排列要求,有继承关系的异常需要子类在上,父类在下
1.3 抛出异常
1.3.1 基本格式
关键字:
	throw
		在方法内特定条件下抛出指定异常
	throws
		在【方法声明】位置,【形式参数列表之后】,告知调用者,当前方法有哪些异常抛出

	用于处理非当前方法操作问题,导致出现的异常,一般情况下是用于处理方法运行过程中因为参数传入,参数处理,运算结果导致的问题,抛出异常。
	throw是一个高级的参数合法性判断!!!
/*                                                      
 * throws 关键字在方法声明位置告知当前方法的调用者,这里存在异常信息                 
 */                                                     
/**                                                     
 * 测试方法                                                 
 *                                                      
 * @param num1 int类型参数                                  
 * @param num2 int类型参数                                  
 * @throws ArithmeticException 如果除数为0,当前方法抛出算术异常        
 */                                                     
public static void test(int num1, int num2)             
		throws ArithmeticException {                    
	                                                    
	/*                                                  
	参数合法性判断 之前的方式 low                                   
	if (0 == num2) {                                    
		System.out.println("你个瘪犊子...坑我");               
		System.exit(0);                                 
	}                                                   
	*/                                                  
	// 参数合法性判断,如果num2 为0, 这里存在隐患                        
	if (0 == num2) {                                    
		/*                                              
		 * 存在异常,这里创建一个异常对象抛出,这里构造方法中                    
		 * 存在无参数构造方法和有参数构造方法                            
		 * 无参数构造方法异常信息为null                             
		 * 有参数构造方法可以传入一个String类型数据,异常信息为指定字符串内容         
		 */                                             
		throw new ArithmeticException("除数不能为0");        
	}                                                   
	                                                    
	// 如果num2的值为0,num1 / num2 操作是存在隐患的,有问题的             
	int ret = num1 / num2;                              
	System.out.println(ret);                            
}                                                        	
finally
无论上面是否有异常finally都会执行,通常用于:
	1.释放资源
	2.无论是否异常都需执行的代码
	【执行地位优于try中的return】
1.3.2 细节问题和注意事项
1. 代码如果运行到throw抛出异常,之后的代码不再运行,之后的代码是成为无参触及代码

2. 代码中存在多种隐患,按照隐含的情况,分门别类处理,不能在同一个条件内抛出两个异常。并且在方法的声明位置,throws之后,不同的异常,使用逗号隔开

3. 当调用带有异常抛出的方法时,对于方法抛出的异常,有两种处理方式,可以捕获处理,也可以抛出处理。
1.4 抛出处理和捕获处理选择
情况分析:
	用户查询指定路径指定名字的文件,存在的异常处理分析过程

5d1bf4191abd3e040b11c071882f2198.png

1.5 异常分类
运行时异常:
	RuntimeException 代码运行过程中出现的异常,没有强制处理的必要性
        ArrayIndexOutOfBoundsException 数组下标越界异常
        NullPointerException 空指针异常
        ArithmeticException 算术异常
	
	运行时异常不强制要求捕获和抛出!!!
	JVM会处理RuntimeException,也就是告知异常的前因后果!!!
	
其他异常:
	强制要求处理,不管是捕获处理,还是抛出处理,都需要进行操作。
	如果未处理!!!直接报错!!!
	
	IDE工具的快速修复
		Eclipse  Ctrl + 1
		IDEA Alt + Enter
1.6 自定义异常
业务逻辑存在需求,但是Java中没有合适的异常来描述对应情况,自定义异常
	
自定义异常格式:
	class MyException extends Exception {
		// 无参数构造方法
		public MyException() {}
		
		// 有参数构造方法,且参数数据类型为String类型
		public MyException(String message) {
			super(message);
		}
	}
	
RuntimeException和Exception选择:
	根据业务需求选择是否需要抛出
【注意】
	Eclipse会提示要求完成一个ID号,可以忽略,存在一个警告,不用管。
package exception;

public class CustomException {
	public static void main(String[] args) {
		Student s = new Student();
		try {
			s.setAge(5060);
		} catch (AgeException e) {
			System.out.println("年龄必须在0~200之间");
			System.out.println(e.toString());//得到异常的简要信息描述,来自于Throwable
			System.out.println(e.getMessage());//得到异常的简要信息描述,来自于Throwable
			e.printStackTrace();
		}
		System.out.println("程序结束");
	}
}

/**
 * 自定义异常: 定义有参无参构造方法,有参构造方法在【自行抛出异常位置】可以增加提示信息
 * 在【捕获异常】处增加e.printStackTrace()可以说输出提示信息
 * 自定义异常会要求完成一个异常,可以忽略,存在一个报警,不用管
 * 定义学生年龄的受查异常
 */
class AgeException extends Exception {
	// 定义无参构造方法
	public AgeException() {
	}

	/**
	 * 异常的有参构造,需要的参数是String类型的参数
	 * @param message 异常的提示信息
	 */
	public AgeException(String message) {
		/*
		 * 通过super关键字调用父类的构造方法
		 */
		super(message);
	}
}

/*
 * 定义学生性别运行时异常
 */
class SexException extends RuntimeException {
	public SexException() {
	}

	public SexException(String message) {
		super(message);
	}
}

class Student {
	private int age;
	private String sex;

	public void setAge(int age) throws AgeException {
		if (age > 200) {
			throw new AgeException("年龄输入非法");
		}
		this.age = age;
	}

	public void setSex(String sex) {
		if (sex.equals("男") || sex.equals("女")) {
			this.sex = sex;
		} else {

			throw new SexException("性别输入非法");
		}
	}
}
1.7 异常处理总结
1. 异常存在的必要性,代码中使用的数据,大多数来源于用户,用户传入数据是一个非常不可靠的情况!!!存在一定错误意识,反馈机制和处理机制。
2. 异常处理方式 
	捕获
	抛出
	要根据使用情况,操作方式,反馈形式来选择对应的处理方式。
3. 自定义异常,了解异常的构造,基本上在开发中用到自定义异常的情况不多见。但是要了解关于异常信息保存的方式。
1.8 接口,继承下的异常
方法名,返回值类型,参数列表和父类相同
子类访问修饰符比父类更大
子类(实现类)中的方法异常不能比父类(接口)更宽