java基础--异常机制
一、异常的体系:
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"); } }