黑马程序员——java基础----面向对象(四) 异常处理

时间:2022-08-16 00:26:35
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- 异常处理 1,什么是异常:
           异常就是程序中出现的问题或者是非正常的情况。
2,异常的由来:
           当我们在玩游戏的时候就会出现一些状况,我们俗称(漏洞)bug。而在程序中,漏洞是无处不在,即使我们认为程序中应该没有错误了,漏洞总会在某个时候就会冒出来,这给我们造成很多困扰。正因为这样,java提供了异常处理机制来协助我们避开可能的错误。
           因为有异常就证明出现问题了,问题也是现实生活中一个具体的事物,也可以通过java类的形式进行描述,并封装成对象。其实就是java对不正常情况进行描述的后的对象的体现。
简单的说:就是java把程序编译和运行时出现的问题进行描述后封装成异常类对象了。
3,异常的一些重要的继承架构
            Throwable
                 |---Error(严重的问题)
                        |---linkagError
                        |---ThreadDeath
                        |---VirtualMachineError
                         ...
                 |---Exception(非严重的问题)(编译时异常)
                        |---ClassNotFoundException
                        |---CloneNotSupportedException
                        |---IllegalAccessException
                         ...
                        |---RuntimeException(执行时异常)
                            |---ArithmeticException
                            |---ArrarStoreException
                            |---ClassCastException   
                             ... 
 特点:异常体系中的所有类以及建立的对象都具备可抛性。也就是说可以被throw和throws关键字所操作。 只有异常体系具备这个特点。
4,异常的处理:
           java提供了特有的语句进行处理。
try{
    需要被检测的代码(捕获)
}
catch(异常类 变量){
    处理异常的代码:(处理方式)
}
finally{
    一定会执行的语句(一般用于关闭资源)
}
5,多异常的处理
          (1)声明异常时,建议声明更为明确的异常,这样处理的可以更具体。
          (2)对方声明几个异常,就对应有几个catch块。如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。
代码:
class Demo
{
int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException//在功能上通过throws的关键字声明了该功能有可能会出现的问题。
{
int [] arr = new int[a];//创建一个数组
System.out.println(arr[4]);//打印数组中第四个元素。
return a/b;//返回a除以b的值
}
}

class ExceptionDemo2
{
public static void main(String[] args)
{

Demo d = new Demo();//创建Demo类对象
try//检测异常代码
{
int x = d.div(4,0);//调用Demo类中的功能获取值
System.out.println("x="+x);//打印所获取的值
}
catch (ArithmeticException e)//处理异常代码
{
System.out.println(e.toString());//打印异常信息
System.out.println("被零除啦");//异常输出
}
catch (ArrayIndexOutOfBoundsException e)//处理异常代码
{
System.out.println(e.toString());//打印异常信息
System.out.println("角标越界拉");//异常输出
}
catch(Exception e){//父类异常


}
System.out.println("over");//结束标记
}
}
6,自定义异常
              我们可以从Exception类或者它的子类派生一个新类,定义自己的异常。
代码:
class FuShuException extends Exception//自定义异常FuShuException继承Exception
{
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 zero",b);//抛出异常对象,参数是错误的信息和输入的错误值。
return a/b;//返回值
}
}
class ExceptionDemo3
{
public static void main(String[] args)
{
Demo d = new Demo();//创建一个Demo类对象
try//检测异常代码
{
int x = d.div(4,-9);//通过对象调用本类的功能,将运算结果给x。
System.out.println("x="+x);//打印x
}
catch (FuShuException e)//处理异常代码
{
System.out.println(e.toString());//打印异常信息
//System.out.println("除数出现负数了");//异常信息
System.out.println("错误的数字的是"+e.getValue());//打印输入错误的值。
}
System.out.println("over");//结束标记
}
}
7,throw和throws的区别
                  (1)throws使用在函数上,后面跟的是异常类,多个异常类用逗号隔开 。
                  (2)throw使用在函数内,后面跟的是异常类对象。
8,RuntimeException(运行时异常) 
                 (1)如果在函数内抛出异常,函数上可以不用声明,编译一样通过。
               (2)如果在函数上声明了该异常,调用者可以不用进行处理。编译一样通过。
 其实运行时异常,就是无法预测这个异常一定会发生,要看程序逻辑写的如何,因而不需要特别使用 try...catch或是在方法上使用throws声明也可以通过编译。
 例如:在使用数组时,并不一定要处理ArrayIndexOutOfBoundsException异常,因为只要程序逻辑写得正确,这个异常就不会发生。
代码:
class Demo
{
int div(int a,int b)//因为函数上没有声明异常,所以调用者不知道此功能会发生异常,但是编译还是没问题的这就是RuntimeException
{

if(b==0)
throw new ArithmeticException("被零除啦");//函数内部抛出一个异常
return a/b;

}
}
class ExceptionDemo4
{
public static void main(String[] args)
{
Demo d = new Demo();//创建Demo类对象

int x = d.div(4,0);//去值//由于函数上没有声明该异常所以调用者根本就不知道有没有异常。
System.out.println("x="+x);//打印x值

System.out.println("over");//结束标记

}
}
对于异常分为两种:
              (1)编译时被检测异常(即可控异常):可以理解为程序执行前所发生的异常,即可以预想到的。
 例如:使用到BufferReader的ReadLine()时,有可能会发IOException异常,要么try..catch,要么在方法上使用throws表示由调用该方法的调用者来处理。
 注意:当发生被检测异常时,thorw和throws的使用
              如果一个功能内部出现了异常,要么内部自己try..catch处理,要么内部使用throw抛出异常对象并在函数上使用throws声明给调用者处理。 当发生不被检测异常时,功能内部抛出异常对象,函数上不用声明,完全交由虚拟机。   
             (2)编译时不被检测的异常(即不可控异常):程序执行时异常,即程序执行过程中所会出现的错误,有的程序员能想到,有的不一定能想到。
例如:在使用数组时,并不一定要处理ArrayIndexOutOfBoundsException异常,    因为只要程序逻辑写得正确,这个异常就不会发生。
9,异常实例
           老师用电脑上课
 上课中会出现的问题: 电脑蓝屏(电脑重启),电脑冒烟(课时无法继续)
注意:当遇到一些问题解决不了的时候,就要向外抛,但是,抛出问题之前要考虑,抛什么?对方能不能解决了?如果解决不了,那么即使你捕获到这个异常,在catch中也是处理不了的,那么索性在catch中就不处理这个异常,把这个异常抛出去,但是,抛出的异常一定要是对方能处理的异常,不一定是捕获的异常!!(非常关键) 自定义异常代码:
class LanPingException extends Exception//自定义蓝屏异常
{
LanPingException(String message)
{
super(message);//调用父类的构造方法,来完成传递发生异常的信息。
}
}
class MaoYanException extends Exception//自定义冒烟异常
{
MaoYanException(String message)
{
super(message);//调用父类的构造方法,来完成传递发生异常的信息。
}
}
class NoPlanException extends Exception//自定义课时无法继续异常
{
NoPlanException(String message)
{
super(message);//调用父类的构造方法,来完成传递发生异常的信息。
}
}
电脑类
class Computer//电脑类
{
private int state=3;//临界值,1,正常 2,蓝屏 3,冒烟
//电脑运行方法
public void run()throws LanPingException,MaoYanException//抛出异常类
{
if(state==2)//蓝屏
throw new LanPingException("蓝屏了");//抛出蓝屏异常对象
if(state==3)
throw new MaoYanException("冒烟了");//抛出冒烟异常对象
System.out.println("电脑运行");//临界值为1时,电脑正常运行。
}
public void reset()//电脑类中特有的方法,重启。
{
state = 1;//临界值1
System.out.println("电脑重启");
}
}
老师类
class Teacher//老师类
{
private Computer cmpt;//电脑对象
private String name;//老师姓名
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("换老师或者放假");//解决办法
}

}
}
10,异常在子父类中覆盖的体现:
                (1)子类在覆盖父类方法时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类。
                (2)如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
                (3)如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。 如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。
代码:
class AException extends Exception//A异常继承Exception
{
}

class BException extends AException//B异常继承A异常
{
}
class CException extends Exception//C异常继承Exception
{
}
//父类
class Fu
{
void show()throws BException//抛出B异常
{

}
// void show()throws AException//抛出A异常
//{
//
//}
}
//子类继承父类
class zi extends Fu
{
void show()throws BException//只能抛出 B 异常,即:由于BException没有子类,所以抛出父类所抛出的异常。
{

}
// void show()throws AException//抛出A,B异常,即:父类异常有子类,所有抛出父类的异常和父类异常子类都可以。
//{
//
//}

}