day09(下)_异常(上)

 

异常概述:

 

/*
 异常: 就是程序在运行时出现不正常情况
 异常由来: 问题也是现实生活中一个具体的事物,
           也可以通过java类的形式进行描述.
           并封装成对象.其实就是java对不正常情况
           进行描述后的对象体现

对于问题的划分:
    两种:一种是严重的问题,一种是非严重的问题
严重的:java通过Error类进行描述
     对于Error一般不编写针对性的代码对其进行处理
非严重:java通过Exception类进行描述
     对于Exception可以使用针对性的处理方式进行处理


无论Error或者Exception都具有一些共性内容
比如: 不正常情况的信息,引发原因等.

Error类和Exception类向上抽取-->Throwable类(可查Java API文档)                                                          
                             (可抛出/异常)
java 提供特有的语句进行处理

try
{

   需要被检测的代码({ }之间的代码抛出异常,均可用下面catch接收)
}
catch(异常类 变量)
{
  处理异常的代码;(处理方式)

}
finally
{

  一定会执行的语句;
}
3.对捕获到的异常对象进行常见方法操作
  String getMessage():返回throwable的详细消息的字符串
*/
//以 除零 为例
class Arithmetic
{

 public int div(int a,int b)
 {
  return a/b;
//
产生一个JVM识别的ArithmeticException问题
//把该问题封装成一个new ArithmeticException(); //
然后把该问题抛给调用该功能(div)的调用者}

}

 
class ExceptionDemo1
{
    public static void main(String[] args) 
    {
     try//检测问题
        //不写try的话,主函数(被JVM调用)没办法处理该问题-->给了JVM-->JVM进行默认处理-->调用默认异常处理机制-->停止程序
        
       //try检测到该问题对象把问题对象丢给catch(捕获)
     {
       int x= new Arithmetic().div(4,0);
       System.out.println("x="+x);//上面的代码已发生问题将不再执行,无任何意义
     }
     catch (java.lang.Exception e)//Exception e=new ArithmeticException(); 
    { 
       System.out.println("除零了");
       System.out.println(“e.getMessage()\t”+e.getMessage());// / by zero
       System.out.println(“e.toString()\t”+e.toString());//异常名称:异常信息

       e.printStackTrace();//异常名称,异常信息,异常出现的位置
     }                      //其实JVM默认的异常处理机制,就是在调用printStatckTrace()方法
                            //打印异常堆栈的跟踪信息
     //以上问题处理完try...catch
    System.out.println("over");
    }
}
/*
关于命名问题:
(运行图二)
如果我的源文件名用了关键字Exception.java
命名这里如果不加java.lang将无法通过编译  
在src.zip的lang文件夹下也有一个Exception.java
JVM并没有编译lang下的Exception.java因此不能使用Exception类
因此加上java.lang,但是强烈不建议源文件名用关键字命名!!!!
*/

图一:

ExceptionDemoLate

图二:

Exception

2.为什么要在函数上声明异常?

/*
为什么要在在函数上声明异常??
    当功能被封装时,只能看见函数声明,根本不知道使用功能会不会发生问题.
    因此编写功能的人,在功能后加了个标识(trows+异常类),在功能上通过throws的关键字声明了该功能有可能会出现问题 
    
    便于提高安全性,让调用者进行处理,不处理则编译失败
*/
class Arithmetic 
{
    public int div(int a,int b) throws Exception//把该问题抛给调用该功能(div)的调用者 
    {
     return a/b;
    }
}
class ExceptionDemo1
{
    public static void main(String[] args) throws Exception//主函数也不处理,把问题抛给了JVM
    {
     int x=new Arithmetic().div(1,0);
     System.out.println("x="+x);
     System.out.println("over");
    
    }
}
ExceptionDemo

 

3.多异常处理:

/*
对多(个 )异常处理
    1.声明异常时,建议声明更为具体的异常.这样处理的更为具体(可以抛该异常的直接或间接父类异常)

    2.对方声明几个异常,就对应有几个catch块
      
      如果多个catch块中的异常出现继承关系,
      父类异常catch块放在最下面.因为父类catch可以处理子类异常,接收子类的catch没用

建议在进行catch处理时,catch中一定要定义具体的处理方式.

不要简单定义一句 e.printStackTrace()
也不要简单的就书写一条输出语句
因为用户看不懂(没任何用处),一般会把问题(信息)用一个文件记录下来(异常日志文件),记录着程序
的运行状况,便于管理员管理和解决.




如果出现未知异常,不要用catch(Exception e)处理
这样做就不能发现异常原因
*/
class Arithmetic
{
  public int div(int a,int b) throws ArithmeticException,ArrayIndexOutOfBoundsException
                              //算术异常,数组越界异常
                              //throws Exception  抛出的异常不具体 
//因为在功能上通过throws的关键字声明了该功能有可能会出现问题 
  {  
   int[] arr=new int[a];
   System.out.println(arr[4]);
   return a/b;
  }
}
class ExceptionDemo2
{
 public static void main(String[] args) //throws Exception//如果调用者不处理该问题,主函数把问题抛给JVM,JVM进行默认处理
    {                                   //一般都是检测问题,然后捕捉进行处理 try..catch
        try
        {
        int x=new Arithmetic().div(4,0);
        System.out.println("x="+x);    
        }
        /*
        catch(Exception e)//这两个异常都能处理,因为多态
        {                 //但是不建议这样写-->处理没有针对性
          System.out.println(e.toString());
        
        }
        //不能与以下两个catch共存
        //因为这个catch块已处理异常,下面两个没用
        */
catch (ArithmeticException e)//针对算术异常处理
        {
              System.out.println(e.toString()+"\n被零除了");
        }
        catch(ArrayIndexOutOfBoundsException e)//针对数组越界异常处理
        {
              System.out.println(e.toString()+"\n数组越界");
        }
        
        System.out.println("over");
    }
}
/*
以上两个异常不会同时发生,
这是因为当角标一越界
System.out.println(arr[4]);
发生异常,函数结束-->抛出数组越界异常
*/

ArrayIndex 

4.自定义异常

/*
为什么要自定义异常???
     因为项目中会出现特有的问题,
    而这些问题并未被java所描述并封装对象
    所以对于这些特有的问题可以按照java的对问题封装的思想.
    将特有的问题.进行自定义的异常封装.

自定义异常:
 
需求: 在本程序中,对于除数是-1,也视为是错误的是无法进行运算的.
那么就需要对这个问题进行自定义的描述

当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作.
    ①要么在内部try..catch处理.
    ②要么在函数上声明让调用者处理.
    一般情况下,函数内出现异常,函数上需要声明


自定义异常:
    必须是自定义类继承Exception
    也可以继承Throwable,Throwable下已有一个Exception体系,因此继承了Exception

继承Exception原因:
    异常体系有一个特点:因为异常类(throws)和异常对象(throw)都被抛出
    因为它们都具备可抛性.这个可抛性是Throwable这个体系中独有的特点.

只有这个体系中的类和对象才可以被throws和throw操作
例如:
class Person
{
 
}
class Demo
{ 
    public void method() throws Person//错误,Person不可抛
  {
  
  }
}
*/
class NegativeException extends Exception
{
  
  private int value;//显示出该负数
  /*
  ①
  private String mes;
  public NegativeException(String mes)
  {
   this.mes=mes;
  
  }
  public String getMessage()//复写父类中的方法
  {
    return mes;
  }
  */
 
  
  /*
  由于Throwable中有构造函数
  public Throwabel(String message)
  因此有了以下代码:
  */

  //把①简化
  //继承关系:Object<-Throwable<-Exception<-NegativeException
  
 public NegativeException(String mes,int value)
  {
    super(mes);      //首先执行Object构造函数初始化—>Throwable构造函数初始化-->接着Exception的-->最后是NegativeException
                     //在下面toString()中会调用从父类继承的getMessage()方法
                       //也就是说:子类内容通过父类初始化

   this.value=value; 
  }
  public int getValue()
  {
    return value;
  }
} 
//以上类的目的为了创建对象
 class Arithmetic
{
 
 public int div(int a,int b) throws NegativeException//①要么在内部try..catch处理.
                                                     //要么在函数上声明让调用者处理.
 {
   if(b<0)
     throw new NegativeException("出现了除数是负数",b);//由于自定义异常JVM不能识别,因此通过手动抛出
                                                    //手动通过throw抛出一个自定义异常对象
  
  return a/b;
 }

}

 
class CustomException
{
    
    public static void main(String[] args) //throws NegativeException
                                           //如果抛给JVM,JVM会报Exception in thread "main" NegativeException..
    {  
      try
      {
        int x= new Arithmetic().div(4,-10);
       System.out.println("x="+x);
      }
      catch(NegativeException e)
      {
          System.out.println(e.toString()+e.getValue());//e.toString()只有异常名称,却没有异常的信息(当NegativeException
                                                                       类中未定义内容时)
      }                                                  //因为系统内部自定义的异常并未定义信息
                                                                 //toString()方法内会调用子类复写的getMessage();   
         
         
      System.out.println("over");      
    }
     
}

CustomException4

5.特殊的异常子类RuntimeException

/*
Exception中有一个特殊的 子类异常RuntimeException体系(运行时异常).

    如果在函数内容抛出异常,函数上可以不用声明,编译一样通过

    如果在函数上声明了该异常.调用者可以不用进行处理(try..catch/throws).编译一样通过.

    之所以不用在函数声明,是因为不需要让调用者处理.
    当该异常发生,希望程序停止,不再向下执行.因为在运行时,
    出现了,无法继续运算的情况,希望停止程序后,让使用者对代码进行修正.

自定义异常时:
    如果该异常的发生,无法在继续进行运算(无法处理),
    就让自定义异常继承RuntimeException
    反之,有些可以处理的异常,就在函数上标识(声明)
    进行处理
对于异常分两种:
     1.编译时被检测的异常
        javac.exe编译时,检测如果在类的方法中抛出非RuntimeException
        或非其子类(例如Exception等),视为可处理的异常
     2.编译时不被检测的异常(运行时异常.RuntimeException及其子类)
        目的让程序停下来

因此在自定义问题时:
  考虑该问题发生时能否处理,不能处理-->继承RuntimeException-->停止程序-->修正代码
  能处理->处理完程序可以继续运行-->继承Exception

*/
class Arithmetic 
{
    public int div(int a,int b) //throws ArithmeticException//注意在这我不声明,也可以通过编译
    {                         
     if(b==0)
      throw new ArithmeticException("被零除了");//注意在这里抛出了一个异常对象
     return a/b;
    }
}
class ExceptionDemo
{
    public static void main(String[] args) //throws ArithmeticException 
    {
     
      int x=new Arithmetic().div(1,0);

       System.out.println("x="+x);
     
     
         System.out.println("over");
     
    }
}

//例二
class Person
{
 public void checkName(String name)
 {
   //if(name.equals("lisi"))//由于name值为null,不能调用Equals
     if("lisi".equals(name))//修正或if(name!=null&&name.equals("lisi"))
     System.out.println("YES");
   else
     System.out.println("NO");
 }
 
}
class Demo
{
 public static void main(String[] args)
 {
   new Person().checkName(null);
 }

}
RuntimeExceptionDemo

异常练习:

/*
老师用电脑上课

开始思考上课中出现的问题:(增强代码健壮性)
  --> 电脑蓝屏
      电脑冒烟
  -->对对象描述,封装成对象

注意:
    当冒烟发生后,会出现讲课进度无法继续(连锁问题)
    这时候就出现了讲师的问题,课时计划无法完成
*/
//蓝屏异常类
class BlueScreenException extends Exception//蓝屏视为可解决问题
{
 public BlueScreenException(String message)
 {
  super(message);
 }
}
//冒烟异常类
class BrokenException extends Exception
{                             
  public BrokenException(String message)
  {
   super(message);
  }
                    
}
//计划无法进行
class NoPlanException extends Exception
{                             
  public NoPlanException(String message)
  {
   super(message);
  }
                    
}


class Pc
{
  private int state=3;//1代表正常
  public void run() throws BlueScreenException,BrokenException //电脑运行时发生异常
  {
    if(state==2)
        throw new BlueScreenException("蓝屏");
    else
      if(state==3)
        throw new BrokenException("冒烟");
   System.out.println("电脑启动");
  }
  public void reset()
  {
   System.out.println("电脑重启");
   state=1;//回到正常状态
   
  }

} 

class Teacher
{
  private String name;
  private Pc p;
  public Teacher(String name)
  {
   this.name=name;
   p=new Pc();
  }
  public void teach() throws NoPlanException
  {
    try
    {
      p.run();
    }
    catch (BlueScreenException e)//处理蓝屏问题
    {
         System.out.println(e.toString());
         p.reset();
    
    }
    
    
    catch(BrokenException e)//接收了 冒烟问题 对象
    {                       //但抛出 无法上课 对象
                                       
      test();
      throw new NoPlanException("无法讲课\n"+e.getMessage());//处理不了冒烟,因此抛出无法上课,符合实际
                                                                     //getMessage()获得原因(为什么不能上课?) 

//throw下面不能有语句                               
//因为根本执行不到-->已抛出,该函数结束-->类似return
    }
    
    
    
    System.out.println("开始讲课");
  }
   public void test()
    {
      System.out.println("练习");//做练习吧
    
    }
}

class ExceptionTest
{
    public static void main(String[] args)
    {
     try
     {
         new Teacher("zhang").teach();
     }
     catch (NoPlanException e)
     {
        
      System.out.println(e.toString()+"\n换老师或放假");

     }
     
    }

}
/*
最后注意:
throws 和 throw 的区别
1.位置
throws使用在函数上
throw使用在函数内
2.
throws后面跟的异常类.可以跟多个以","隔开
throw后跟的是异常对象(异常类的实例) 

*/
ExceptionTest
posted @ 2013-03-08 22:05  伊秋  阅读(261)  评论(0编辑  收藏  举报