异常Exception


【疑点】

带有finally的语句执行顺序

1.异常概述

程序运行的过程中的非正常状况,与错误(Error)不同,Error是程序无法处理的状况,异常是可以通过程序来解决的状况,Exception与Error都是Throwable的直接子类

任何程序都有可能出现大量的问题或者异常,如果不对程序进行异常的处理,程序会在出现异常的代码处中断执行,导致程序无法继续。

异常存在的意义:让我们的程序在出现异常的代码之后还能够继续执行,而不至于直接中断后面代码的执行
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:Exception是所有异常的根
--| RuntimeException(非检测异常):运行期异常,可处理可不处理,可通过编译
--| CheckException(受查异常,检测异常):必须处理,不处理不能编译

    检测异常:编译期间就要求处理的异常,后者try~catch,要么throws声明异常;
    File f = new File();
    f.creatNewFile();//此处会报警

1.3 异常五个关键字

try:尝试执行一段有可能发生异常的代码

catch:捕获,发生异常后要处理的代码块

finally:最终,不管是否发生异常,该代码块都将被执行

throws:异常的声明,在方法的头部要声明该方法中可能出现的所有异常对象

throw:在方法中出现异常是将异常交给下一个主调方法来处理

1. 异常处理

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

当场处理好,拒之门外。
	这两种方式就是Java中处理异常的方式
	【捕获】 有能力处理你就捕获,自己的问题你就捕获
	【抛出】 没有办法处理,或者不是自己的问题,和自己无关,因别人导致的错误,抛出
	
	捕获 try~~catch
	抛出 throw在语句块处,throws在声明处
	
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. 捕获多个异常时,无继承关系的异常没有上下排列要求,有继承关系时需要子类异常在上,父类异常在下

8.两个相同的catch捕获时,下面的那个会成为unreachable code

9.异常的类型(try部分)和(catch部分)不匹配时,catch部分不会捕获不匹配的异常(try部分)
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);                            
}                                                        	
1.3.2finally
无论上面是否有异常finally都会执行,通常用于:
	1.释放资源
	2.无论是否异常都需执行的代码

finally 和return的执行顺序。return可以加载try和finall的模块中,不能加在finally中,加在finally中会警告

finally执行顺序

package exception;

public class TryCatchFinally04 {

	public static void main(String[] args) {
		System.out.println(getNum());
	}
	
	/**
	 * try catch中return的变量,即使该变量在finally代码块中做了修改,
	 * 	但是return的瞬间点的值是多少,我们该方法最终的返回值还是当时瞬间点的值。
	 * 
	 * @return
	 */
	public static int getNum() {
		int a = 0;
		try {
			return a;
		} catch (Exception e) {
			e.printStackTrace();
			return -a;
		}finally {
			a++;
			//return ++a;
		}
		//return 0;
	}
}

0
package exception;

public class TryCatchFinally03 {

	public static void main(String[] args) {
		System.out.println(getNum());
	}
	
	/**
	 * finally的代码块会在try或者catch的return之前执行
	 * 	假如finally中存在return,则整个方法的返回值就是finally的代码的return值
	 * @return
	 */
	public static int getNum() {
		try {
			System.out.println("try");
			System.out.println(1 / 0);
			//return 1;
		} catch (Exception e) {
			System.out.println("catch");
			e.printStackTrace();
			//return -1;
		}finally {
			System.out.println("finally");
		}
		return 0;
	}
}
1.3.3 细节问题和注意事项
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(60);
		} catch (AgeException e) {
			System.out.println("年龄必须在0~200之间");
			System.out.println(e.toString());//得到异常的简要信息描述,来自于Throwable
			System.out.println(e.getMessage());//得到异常的简要信息描述,来自于Throwable
			e.printStackTrace();
		}
		
		s.setSex("afds");
		System.out.println("程序结束");
		
	}
}

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

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

/*
 * 定义学生性别运行时异常
 * 
 * SexException继承的是运行异常,在代码块中只抛出异常不在声明处进行声明不会报警
 * 如果继承的是受查异常,只抛出不声明不会存在异常
 */
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("女"))) {
			throw new SexException("性别输入非法");
		} else {
			this.sex = sex;
		}
	}
}
1.7 异常处理总结
1. 异常存在的必要性,代码中使用的数据,大多数来源于用户,用户传入数据是一个非常不可靠的情况!!!存在一定错误意识,反馈机制和处理机制。
2. 异常处理方式 
	捕获
	抛出
	要根据使用情况,操作方式,反馈形式来选择对应的处理方式。
3. 自定义异常,了解异常的构造,基本上在开发中用到自定义异常的情况不多见。但是要了解关于异常信息保存的方式。
1.8 接口,继承下的异常
方法名,返回值类型,参数列表和父类相同
子类访问修饰符比父类更大
子类(实现类)中的方法异常不能比父类(接口)更宽

【请简述你对异常的理解】

异常是程序运行时的意外情况。
异常位于java.lang包下,继承自Throwable类,为所有异常的基类。
程序运行时不发生异常情况时不可能的,程序发生异常时会停止运行,不能完成对应的服务。对于程序中的异常,我们可以通过一些对应的处理措施可以预防这种情况,在程序发生异常时还能继续运行下去,完成应有的功能。
异常可分为运行时异常和受查异常,受查异常在程序进行编写时就有错误提示,我们可以马上发现并进行修正。运行时异常需要我们了解程序运行情况,对可能出现问题的程序进行捕获或者声明。
程序在用户界面可能发生异常时要进行捕获处理,不能将异常展现给用户;在非用户界面,我们根据实际情况对异常进行捕获,抛出或者修正异常。
原文地址:https://www.cnblogs.com/raising/p/12969246.html