《学习笔记Day17》异常类编译异常以及运行异常详细介绍&throw和throws关键字以及比较

一、异常

(一)异常的概述
1、在Java运行过程中,出现了不正常的情况,称为异常
2、异常就是一个对象,描述那些和正常情况不相符的异常情况,包含了异常情况的原因、详细信息、异常类型、错误位置等,这些内容都被封装在异常对象里
3、异常也是一种处理异常情况的机制,可以对异常对象进行捕获、或者使程序发生跳转甚至停止运行

(二)异常的体系

1、Throwable:可抛出的,是异常体系和错误体系的总父类,所有的异常或者是错误对象都是Throwable的子类类型。只有Throwable的体系内的类型,才能进行异常处理。
2、Error:错误,是Throwable的子类,用于描述那些无法捕获和处理的错误情况,属于非常严重的错误:StackOverFlowError
3、Exception:异常,是Throwable的子类,用于描述那些可以被捕获和处理的例外情况,属于不太严重的错误:NullPointerException
4、Exception是Java中所有异常类型的总父类,只要是异常类型,都是它的子类
5、RuntimeException:运行时异常,是Exception类的子类。RuntimeException及其子类都是运行时异常,除此外,所有的异常都是编译时异常。所谓运行时异常,就是在编译阶段不做检查;所谓编译时异常,就是在编译阶段,会额外的做检查。
在这里插入图片描述

(三)JVM默认处理异常机制

1、在代码的某个位置,出现了和正常情况不同的情况,就将异常信息封装到一个异常对象中
2、将异常对象抛给调用该方法的方法
3、某个方法接收到其他方法抛来的异常对象,也没有办法处理,会继续向上抛,最终抛给主方法,主方法也没有办法处理,将异常对象抛给虚拟机
4、JVM是我们手动调用的,JVM会将异常对象的所有信息,通过错误流打印出来,并且结束JVM的运行
5、总结:JVM默认处理异常的方式:一层一层向上抛,JVM接收到之后打印异常信息并结束自己

(四)手动处理异常的方式

1、有两大类的处理异常的方式:

(1)异常的声明:某个方法存在编译时异常,编译期就无法通过,需要在出现编译时异常的方法声明上,对可能会发生的异常类型进行声明
(2)异常的捕获:出现异常之后,可以通过某些代码格式对异常对象进行捕获和处理,此时,程序出现的异常对象,就不会再向上抛,而是被捕获下来,我们做出相应的处理后,出现异常代码之后的代码,会继续运行。我们可以自己定义处理异常的逻辑。

2、捕获处理异常的格式:
(1)try…catch
(2)try…catch…catch…catch…
(3)try…catch…finally
(4)try…finally

(五)try…catch格式

1、try,关键字,含义:试一试,可能出现问题的代码放在try模块中
2、catch,关键字,含义:捕获,当真的出现了异常时,问题代码会抛出一个异常对象,可以通过catch模块将异常对象捕获下来,就不会按照JVM默认机制一层一层向上抛了,并且还能在catch模块中对异常对象进行处理
3、格式:

try {
可能出现异常的代码
} catch(可能出现异常的类型 标识符) {
出现这种异常后的处理方式
}

4、运行机制:
(1)try之前的代码正常运行
(2)运行try中的代码
(3)如果try中代码没问题,则catch不执行,直接执行try…catch之后的代码
(4)如果try中代码有问题,抛出异常对象,则catch尝试捕获
(5)如果catch声明的异常类型能匹配异常对象的类型,则捕获进行处理,try…catch之后的代码正常执行
(6)如果catch声明的异常类型不能匹配异常对象的类型,则无法捕获,按照JVM默认机制处理,try…catch之后的代码不执行
(7)额外的,try中如果某句代码抛出异常对象,try出现异常代码之后的代码,不会再执行,会直接进catch捕获
(8)捕获到异常对象后的处理方式:记录日志、反复运行、鸵鸟政策等

public static void main(String[] args) {
	System.out.println("很快啊");
		
		try {
			int i = 10 / 0;//new ArithmeticException();
			System.out.println("传统功夫点到为止");
			System.out.println(i);
			
		} catch (ArithmeticException ae) {//ArithmeticException ae = new ArithmeticException();
		}
		System.out.println("后面那三个年轻人不讲武德");
	}

(六)try多catch

1、在一段代码中,可能会出现多种异常(虽然可能出现多种异常,但是实际发生的时候,只会抛出多种类型异常的其中一种类型的对象),所以要准备多种异常处理机制
2、格式:
try {
可能会出现异常的代码
} catch(异常类型1 标识符) {
处理异常的方式1
} catch(异常类型2 标识符) {
处理异常的方式2
} … {
} catch(异常类型n 标识符) {
处理异常的方式n
}

3、执行流程:
(1)执行try中代码,如果没有异常,catch就不执行,直接执行catch之后的代码
(2)如果try中某句代码发生了异常,try中这句代码之后的代码就不会再去执行了,而是直接跳转到后面的catch模块
(3)当try中抛出异常对象,会按照从上到下的顺序,匹配每一个catch模块,哪一个catch匹配到了,就执行哪一个处理方式,处理完毕之后,再去执行try…catch之后的代码
4、注意事项:
(1)如果是多catch的情况,一般子类类型异常的声明写在上面,父类类型异常的声明写在下面,因为当异常对象抛出时,按照从上到下的顺序匹配catch,如果父类在上,写在下面的子类就永远无法被匹配
(2)在JDK7之后,可以对异常类型进行逻辑运算,实际上就是使用【|】来表示多种异常类型,可以有相同的处理方式,还能够结合多catch
catch(异常类型1 | 异常类型2 | 异常类型3 标识符) {
以上异常类型的共同处理方式
} catch (异常类型4 | 异常类型5 标识符) {
处理手段
}

(七)try…catch…finally

1、finally,关键字,含义:最后。当代码中有必须要去执行的代码,可以放在finally表示的模块中
2、格式:
try {
可能出现异常的代码
} catch(可能出现异常的类型 标识符) {
出现这种异常后的处理方式
} finally {
一定会被执行的代码
}

3、finally模块的作用:
(1)如果try中代码出现了异常,就会抛出异常对象,之后直接尝试用catch进行捕获,万一没有捕获到,就会按照JVM默认机制处理,后续的一些代码就不会被执行。如果某些代码一定要执行,就可以将这些代码放入finally模块中,即便是catch捕获不到异常对象,按照JVM默认方式处理,在finally模块中的代码也一定会被执行
(2)作用:一般用于关闭资源

(八)try…finally

格式:
try {
可能出现异常的代码
} finally {
一定会被执行的代码
}

3、作用:
(1)这种格式无法捕获异常,目的就是在于一旦出现异常,按照默认机制处理,只是在关停虚拟机之前,需要关闭一些资源等
(2)假设如果有两句代码都要执行,两句都可能出现异常,那么将一句代码写在try中,另一句写现在finally中,第一句出现问题,也会保证第二句也能执行

(九)编译时异常和运行时异常

1、无论是编译时异常还是运行时异常,真正发生的时候都在运行期。
2、区别:

(1)继承的角度:Exception除了RuntimeException之外,它本身其子类都是编译时异常;RuntimeException及其子类都是运行时异常
(2)代码表现角度:

1)编译时异常:会在代码编译期进行语法检测,一旦有编译时异常,在编译期是不会通过编译的,必须通过异常处理的两种手段之一去处理:异常的声明,异常的捕获。当然,在运行阶段,编译时异常也不一定会发生。

2)运行时异常:在编译阶段没有任何提示,运行阶段不发生就不发生了,如果发生会直接抛出异常对象

(十)继承体系中的常用方法

1、异常体系中,绝大部分异常类型只有构造,没有成员方法,所有的成员方法都在父类Throwable中,目的是为了使用统一的手段处理不同的异常对象
2、构造方法:

(1)Throwable() 创建异常对象,异常对象中的消息消息为null
(2)Throwable(String message)
创建异常对象,异常对象中具有指定的详细信息
(3)Throwable(Throw cause) 创建一个带有异常原因的异常对象
(4)Throwable(String message, Throw cause) 创建一个带有详细信息和异常原因的异常对象

3、成员方法:

(1)getCause() 获取异常对象中的异常原因
(2)getMessage() 获取异常对象的详细信息
(3)toString() 打印异常的简短描述
(4)printStackTrace() 打印栈轨迹

(十一)throw关键字

1、throw,关键字,含义:抛出。用于抛出一个异常对象
2、程序在运行过程中,发生异常的时候抛出的是一个实实在在的异常对象。我们在实际应用中,如果代码中哪里有和生活不相符的情况,可以将异常信息等封装为一个异常对象,通过throw关键字将异常对象抛出
3、作用:创建一个异常对象,使用throw关键字抛出,实现了程序的跳转甚至结束
4、说明:当代码正常运行的时候,运行时异常不会发生,就相当于没有任何异常对象;当代码运行过程中出现了异常情况,才会创建异常对象并且抛出。


public class Demo07_Throw {
	
	public static void main(String[] args) {
		Person p = new Person();
		
		new Person("zhangsan", -1);
		
		try {
			System.out.println("!!!!!!!!!!!!");
			p.setAge(-20);//输入-20调用异常抛出
			System.out.println(p.getAge());
			
		} catch (RuntimeException e) {
			//e.printStackTrace();
			//p.setAge(18);
			
			System.out.println(e.getMessage());
		}
		
		System.out.println(p.getAge());
	}
}

*********************************************************************************************************************************************************

public class Person {
	private String name;
	private int age;
	
	public Person() {
		super();
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		
		if (age >= 0 && age <= 130) {
			this.age = age;
		} else {
			throw new RuntimeException("年龄输入不合法");
		}
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		if (age >= 0 && age <= 130) {
			this.age = age;
		} else {
			//System.out.println("年龄输入不合法");
			/*RuntimeException re = new RuntimeException("年龄输入不合法");
			
			throw re;*/
			
			throw new RuntimeException("年龄输入不合法");
		}
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}

(十二)throws关键字

1、throws,关键字,含义:抛出**。用于声明一个或者多个异常类型**
2、在某个方法中,如果存在一些编译时异常,并且这些编译时异常还尚未处理,就会报错阻止编译,我们就必须要对编译时异常进行处理:捕获或者声明。如果需要声明编译时异常,就需要在方法的声明上,参数列表之后,跟上关键字throws,并且注明声明一个或者几个异常类型。
3、格式:
修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2, 异常类型3… {
方法体
}

4、注意事项:

(1)如果发生的是编译时异常,那么既可以进行捕获处理,也可以进行声明处理。声明处理只是具有提示作用,提示此处可能会出现哪些类型的异常,如果将来运行真的出了问题,还是会抛出一个实实在在的异常对象
(2)如果发生的是一个运行时异常,不需要声明处理,最多只需要捕获处理,也可以选择不处理。但是当运行时真正发生了运行时异常,会真的抛出一个异常对象
(3)A方法如果声明了编译时异常,那么B方法调用A方法也会有编译时异常,此时B方法就必须要针对编译时异常做出处理,要么声明,要么try…catch。如果B方法进行了try…catch,那么B方法的调用者C方法就不会再有编译时异常了,如果B方法进行了异常的声明,那么C方法要继续考虑处理编译时异常的情况。
(4)声明异常的原则:尽量声明少的、声明小的异常类型

(十三)throw和throws关键字的比较

1、throw是对已经出现的异常对象进行抛出,throws关键字是对可能发生的异常类型进行声明
2、throw是对异常对象实实在在的抛出,一旦使用了throw关键字,就一定会有一个异常对象出现;throws关键字是对多个可能出现的异常类型的声明,即使声明了,也有可能一个都不出现
3、throw后面跟一个异常对象;throws后面跟多个异常类型
4、throws声明异常类型的时候,声明尽量少尽量小的异常类型

(十四)方法重写的补充说明

1、在子父类中,方法名称相同,参数列表相同,与返回值类型有关
2、有关:父类方法返回值是A类,子类重写的方法返回值是A或者A的子类
3、私有方法不能被重写
4、重写的方法权限可以保持不变,或者越来越大,不能越来越小
5、如果父类方法声明了A类型的异常,子类重写的方法只能声明A或者A的子类类型的异常
6、如果父类方法没有声明异常,子类重写的方法有编译时异常,只能进行try…catch,不能throws

(十五)自定义异常

1、异常报错时,异常类型就能见名知意知道是什么类型的问题,但是由于JDK中提供的异常类型有限,不能很好地覆盖我们开发中出现的各个类型的问题,所以需要我们自定义异常类型,以精确表示出现的异常
2、自定义异常的步骤:
(1)创建一个异常类型,类名做到见名知意
(2)需要让自定义类型加入异常体系
1)如果自定义的是运行时异常,就继承RuntimeException
2)如果自定义的是编译时异常,就继承Exception
(3)因为所有异常为了方便统一处理,都会使用Throwable中的方法,并且为了以后方便创建异常对象和处理异常对象,我们需要在自定义异常类型中,根据父类构造方法的情况,提供相应构造

public class Demo10_TestDefiendException {
	
	public static void main(String[] args) {
		Police p = new Police();
		
		try {
			p.setAge(-10);
		} catch (IllegalAgeException e) {
			e.printStackTrace();
		}
	}
}
public class IllegalAgeException extends Exception {

	public IllegalAgeException() {
		super();
	}

	public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}

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

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

	public IllegalAgeException(Throwable cause) {
		super(cause);
	}
}
public class Police {
	private String name;
	private int age;

	public Police() {
		super();
	}

	public Police(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) throws IllegalAgeException {
		if (age >= 0 && age <= 120) {
			this.age = age;
		} else {
			throw new IllegalAgeException("年龄非法,请输入[0,120]之内的年龄");
		}
	}

	@Override
	public String toString() {
		return "Police [name=" + name + ", age=" + age + "]";
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿福真的不想掉头发

大爷?赏点?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值