一、异常的体系:
Throwable
---Error
---Excepeion
Error: 通常出现重大问题如:运行的类不存在或者内存溢出等。不编写针对代码对其处理
Exception: 在运行时出现的一些状况,可以通过try catch finally处理
Error与Exception相同点:
不正常情况的信息,引发原因等。
Exception和Error的子类名都是以父类名作为后缀
异常体系的特点:
异常体系中的所有类以及建立的对象都具备可抛性。
也就是说可以被throw和throws关键字所操作。
只有异常体系具备这个特点。
Throwable中的方法
getMessage():获取异常信息,返回字符串
toString():获取异常类名和异常信息,返回字符串
printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置,返回void
printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查
二、异常分两种:
1、编译时被检测的异常
需要进行处理,即try或者throw,否则编译失败
该异常被throws标识,代表可以被处理
2、运行时异常(RuntimeException以及其子类)
编译时,不需要处理,编译器不检查
该异常的发生,建议不处理,让程序停止,需要对代码进行修正
三、throws 和throw
作用:
throws 用于标识函数暴露出的异常。
throw 用于抛出异常对象
区别:
throws 用在函数上,后面跟异常类名。
throw用在函数内,后面跟异常对象。
四、异常处理
当函数内容有throw抛出异常对象,并未进行try-catch处理,必须要在函数上声明,否则编译失败。
注意:
RuntimeException除外,也就说,函数内如果抛出的RuntimeExcpetion异常,函数上可以不用声明。
try{
需要检测的代码
}catch(异常类 变量){
处理的代码
}finally{
一定会执行的代码
}
finally注意事项:
1,finally中定义的通常是 关闭资源代码。因为资源必须释放。
2,finally只有一种情况不会执行。当执行到System.exit(0);(虚拟机退出),fianlly不会执行。
3种处理的结合方式:
try-catch、
try-finally、try-catch-finally
记住一点:catch是用于处理异常,如果没有catch,就代表异常没有被处理过,如果该异常是检测时异常,那么必须声明。
异常处理原则:
1、当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作,要么在内部try-catch,要么在函数上声明让调用者处理
2、声明异常时,建议声明更为具体的异常,这样处理的可以更具体
3、对方声明几个异常,就对应几个catch块,不要定义多余的catch块
如果多个catch块中的异常时继承的关系,父类异常应该放在最下面。(如果父类放上面,则子类异常就执行不到了)
4、建议在catch处理时,catch中一定要定义具体的处理方式,便于查错。
当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
try{
throw new AException();
}
catch (AException e){
throw e;
}
5、如果该异常处理不了,但并不属于该功能出现的异常。可以将异常转换后,在抛出和该功能相关的异常。
或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,让调用者知道出现了异常,并处理。
也可以将捕获异常处理后,转换新的异常。
try{
throw new AException();
}
catch (AException e){
// 对AException处理。
throw new BException();
}
五、自定义异常
1、由来:
因为项目中会出现特有的问题,而这些问题并未被java所描述并封装成对象,所以对 于这些特有的问题可以按照java的对问题封装的思想,
将特有的问题,进行自定义的 异常封装。
2、自定义异常好处:
按照java的面向对象思想,将程序中出现的特有问题进行封装。
3、自定义异常需要继承Exception或者RuntimeException
原因:
1>异常体系有一个特点:因为异常类和异常对象都被抛出,他们都具备可抛性,而这个可抛性是Throwable这个体系中独有特点,
只有这个体系中的类和对象才可以被throws和throw操作。
2>让该类具备操作异常的共性方法
4、如何定义异常信息呢?
因为父类中已经把异常信息的操作都完成了,所以子类只要在构造时,将异常信息传递 给父类通过super语句。那么就可以直接通过
getMessage方法获取自定义的异常信息。
示例:
这里假不允许输入负数
我们可以在自定义异常获取更多的信息,方法同样是通过构造函数传入
class FuShuException extends Exception //getMessage();{
private int value;
FuShuException(){
super();
}
FuShuException(String msg,int value){
super(msg);
this.value = value;
}
public int getValue()
{
return value;
}
}
class Demo{
int div(int a,int b)throws FuShuException{
if(b<0)
throw new FuShuException("出现了除数是负数的情况------ / by fushu",b);//手动通过throw关键字抛出一个自定义异常对象。
return a/b;
}
}
class ExceptionDemo3{
public static void main(String[] args) {
Demo d = new Demo();
try{
int x = d.div(4,-9);
System.out.println("x="+x);
}
catch (FuShuException e){
System.out.println(e.toString());
//System.out.println("除数出现负数了");
System.out.println("错误的负数是:"+e.getValue());
}
System.out.println("over");
}
}
五、RuntimeException:
Exception中有一个特殊的子类异常:RuntimeException运行时异常。
1、RuntimeException不用声明的情况:
如果在函数内部抛出该异常或其子类,函数上可以不用声明,编译一样通过
如果在函数上声明了该异常或其子类,调用者可以不用声明,编译一样通过
2、不用在函数声明的原因:
不希望让调用者处理,当该异常发生,希望程序停止。因为在运行时,出现了无法继续 运算的情况,希望调用者停止程序后,对代码进行修正。
自定义异常时,如果该异常的发生,无法在继续进行运算,就让自定义异常继承RuntimeException。
六、异常在子父类覆盖中的体现;
1,子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父 类的异常或者该异常的子类。
2,如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子类 或者子集。
3,如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出 异常。如果子类方法发生了异常。就必须要进行try处理。绝对不能抛。
七、练习:
练习一
需求:
1、对于老师用电脑上课中出现的问题进行处理
2、讲课中出现的问题:电脑蓝屏、电脑冒烟
3、可是当冒烟发生后,出现讲课进度无法继续
出现了讲师的问题:课时计划无法完成。
4、要对问题进行描述,封装成对象。
//蓝屏异常
class LanPingException extends Exception{
LanPingException(String message){
super(message);
}
}
//冒烟异常
class MaoYanException extends Exception{
MaoYanException(String message){
super(message);
}
}
//计划外异常
class NoPlanException extends Exception{
NoPlanException(String msg){
super(msg);
}
}
//计算机类
class Computer{
private int state = 3;
//计算机运行时可能出现异常,需要抛出
public void run()throws LanPingException,MaoYanException{
if(state==2)
throw new LanPingException("蓝屏了");
if(state==3)
throw new MaoYanException("冒烟了");
System.out.println("电脑运行");
}
public void reset(){
state = 1;
System.out.println("电脑重启");
}
}
//讲师:有姓名,需要一台电脑
class Teacher{
private String name;
private Computer cmpt;
Teacher(String name){
this.name = name;
cmpt = new Computer();
}
//讲课的过程,对于自己可以处理的就处理,不可处理的抛出
public void prelect()throws NoPlanException{
try{
cmpt.run();
}
catch (LanPingException e){
cmpt.reset();//电脑蓝屏,自己可以处理,重启即可
}
catch (MaoYanException e){
//让同学先做练习
test();
//电脑冒烟,自己无法处理,将异常转换为其他异常抛出
throw new NoPlanException("课时无法继续"+e.getMessage());
}
System.out.println("讲课");
}
//在处理冒烟问题之前,先做其处理,让同学做练习
public void test(){
System.out.println("练习");
}
}
class ExceptionTest {
public static void main(String[] args) {
Teacher t = new Teacher("毕老师");
try{
t.prelect();
}
catch (NoPlanException e){
System.out.println(e.toString());
System.out.println("换老师或者放假");
}
}
}
练习二
需求:
1、有一个圆形和长方形,都可以获取面积。
2、对于面积如果出现非法的数值,视为是获取面积出现问题。
3、问题通过异常来表示,对这个程序进行基本设计。
示例说明:
对于面积的求取,主要是输入数据的异常,所以这里定义了一个非法数据异常,
当出现非法数字时,程序不需要再进行下去,所以这里继承了RuntimeException,不需声明
对于一些经常用到的常量,我们可以定义为public static final类型,共享一份,不可修改
class NoValueException extends RuntimeException{
NoValueException(String message){
super(message);
}
}
interface Shape{
void getArea();
}
class Rec implements Shape{
private int len,wid;
Rec(int len ,int wid){//throws NoValueException
if(len<=0 || wid<=0)
throw new NoValueException("出现非法值");
this.len = len;
this.wid = wid;
}
public void getArea(){
System.out.println(len*wid);
}
}
class Circle implements Shape{
private int radius;
public static final double PI = 3.14;
Circle(int radius){
if(radius<=0)
throw new NoValueException("非法");
this.radius = radius;
}
public void getArea(){
System.out.println(radius*radius*PI);
}
}
class ExceptionTest1{
public static void main(String[] args) {
Rec r = new Rec(3,4);
r.getArea();
Circle c = new Circle(-8);
System.out.println("over");
}
}