A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始







4、继承

4.10 异常

    4.10.1 异常的体系

    异常:是在运行时期发生的不正常情况。

    在java中用类的形式对不正常情况进行了描述和封装对象。描述不正常的情况的类,就称为异常类。

    1. 以前正常流程代码和问题处理代码相结合,现在将正常流程代码和问题处理代码分离,提高阅读性。
    2. 其实异常就是java通过面向对象的思想将问题封装成了对象,用异常类对其进行描述。
    3. 不同的问题用不同的类进行具体的描述。比如角标越界、空指针异常等等。
    4. 问题很多,意味着描述的类也很多,将其共性进行向上抽取,形成了异常体系。

    不正常情况分成了两大类:

    Throwable:无论是error,还是异常、问题,问题发生就应该可以抛出,让调用者知道并处理。
    该体系的特点就在于Throwable及其所有的子类都具有可抛性。

    可抛性到底指的是什么呢?怎么体现可抛性呢?
    其实是通过两个关键字来体现的:throws throw,凡是可以被这两个关键字所操作的类和对象都具备可抛性。


    1. 一般不可处理的:Error
       特点:是由jvm抛出的严重性问题。
       这种问题发生,一般不针对性处理,直接修改程序。
    2. 可以处理的:Exception

    该体系的特点:
    子类的后缀名都是用其父类名作为后缀,阅读性很强。


    Throwable中的方法:
    1. getMessage():获取异常信息,返回字符串。
    2. toString():获取异常类名和异常信息,返回字符串。
    3. printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置,返回值void。
    4. printStackTrace(PrintStream s):通常用该方法将异常内容保存在日志文件中,以便查阅。


    示例:
  1. class Demo{
  2.        public static int method(int[] arr, int index){
  3.              if(arr == null){
  4.                    throw new NullPointerException("数组的引用不能为空!");
  5.              }
  6.              if(index >= arr.length ){
  7.                    throw new ArrayIndexOutOfBoundsException("数组的角标越界:" + index);
  8.              }
  9.              return arr[index];
  10.        }
  11. }
  12. class ExceptionDemo{
  13.        public static void main(String[] args){
  14.             int[] arr = new int[3];
  15.             Demo.method(arr,30);
  16.        }
  17. }
复制代码
   运行结果:


    4.10.2 自定义异常

    可以自定义出的问题称为自定义异常。
    对于角标为负数的情况,可以用负数角标异常来表示,负数角标这种异常在java中并没有定义过。
    那就按照java异常的创建思想,面向对象,将负数角标进行自定义描述,并封装成对象。

    这种自定义的问题描述称为自定义异常。

    P.S.
    如果让一个类成为异常类,必须要继承异常体系,因为只有成为异常体系的子类才有资格具备可抛性,才可以被两个关键字所操作:throws、throw。

    自定义类继承Exception或者其子类,通过构造函数定义异常信息。


    示例:

  1. Class DemoException extends Exception
  2. {
  3.      DemoException(String message)
  4.      {
  5.           super(message);
  6.      }
  7. }
复制代码
   

    通过throw将自定义异常抛出。

    throws和throw的区别:
    1. throws用于标识函数暴露出的异常类,并且可以抛出多个,用逗号分隔。throw用于抛出异常对象。
    2. thorws用在函数上,后面跟异常类名。throw用在函数内,后面跟异常对象。


    定义功能方法时,需要把出现的问题暴露出来让调用者去处理,那么就通过throws在函数上标识。
    在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。


    示例:
  1. class FuShuIndexException extends Exception{
  2.       FuShuIndexException(){}

  3.       FuShuIndexException(String msg){
  4.              super(msg);
  5.       }
  6. }

  7. class Demo{
  8.        public static int method(int[] arr, int index) throws FuShuIndexException{
  9.              if(index < 0){
  10.                    throw new FuShuIndexException("数组的角标是负数啦!" );
  11.              }
  12.              return arr[index];
  13.        }
  14. }

  15. class ExceptionDemo{
  16.        public static void main(String[] args) throws FuShuIndexException{
  17.             int[] arr = new int[3];
  18.             Demo.method(arr,-30);
  19.        }
  20. }
复制代码
   运行结果:



    异常的分类:
    1. 编译时被检测异常:只要是Exception和其子类都是,除了特殊子类RuntimeException体系。
        这种问题一旦出现,希望在编译时就进行检测,让这种问题有对应的处理方式。
        这样的问题都可以针对性的处理。


    2. 编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类。
        这种问题的发生,无法让功能继续,运算无法运行,更多是因为调用的原因导致的或者引发了内部状态的改变导致的。
        那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行调整。
        所以自定义异常时,要么继承Exception,要么继承RuntimeException。


    示例:

  1. class FuShuIndexException extends RuntimeException{
  2.       FuShuIndexException(){}

  3.       FuShuIndexException(String msg){
  4.              super(msg);
  5.       }
  6. }

  7. class Demo{
  8.        public static int method(int[] arr, int index){//RuntimeException没有必要用throws抛出,并不是必须要处理
  9.              if(index < 0){
  10.                    throw new FuShuIndexException("数组的角标是负数啦!" );
  11.              }
  12.              return arr[index];
  13.        }
  14. }
复制代码
   运行结果:



    P.S.
    RuntimeException是那些可能在Java虚拟机正常运行期间抛出的异常的超类。
    可能在执行方法期间抛出但未被捕获的RuntimeException的任何子类都无需在throws子句中进行声明。


    异常处理的捕捉形式:
    可以对异常进行针对性处理的方式。

    具体格式是:
    try{
         //需要被检测异常的代码。
    }
    catch(异常类 变量) //该变量用于接收发生的异常对象
    {
         //处理异常的代码。
    }
    finally{
         //一定会执行的代码;
    }


    P.S.

    finally代码块只有一种情况不会被执行,就是在之前执行了System.exit(0)。

    处理过程:
    try中检测到异常会将异常对象传递给catch,catch捕获到异常进行处理。
    finally里通常用来关闭资源。比如:数据库资源,IO资源等。
    需要注意:try是一个独立的代码块,在其中定义的变量只在该变量块中有效。
    如果在try以外继续使用,需要在try外建立引用,在try中对其进行初始化。IO,Socket就会遇到。


    示例:
  1. class FuShuIndexException extends RuntimeException{
  2.       FuShuIndexException(){}

  3.       FuShuIndexException(String msg){
  4.              super(msg);
  5.       }
  6. }

  7. class Demo{
  8.        public static int method(int[] arr, int index) throws NullPointerException,FuShuIndexException{
  9.              if(arr == null)
  10.                    throw new NullPointerException("没有任何数组实体");
  11.              if(index < 0){
  12.                    throw new FuShuIndexException("数组的角标是负数啦!");
  13.             }
  14.              return arr[index];
  15.       }
  16. }

  17. class ExceptionDemo{
  18.        public static void main(String[] args){
  19.             int[] arr = new int[3];
  20.             try{
  21.                   int num = Demo.method(arr,-30);
  22.                   System.out.println("num:" + num);
  23.             } catch(NullPointerException e){
  24.                   System.out.println(e);
  25.             } catch(FuShuIndexException e){
  26.                   System. out.println("message:" + e.getMessage());
  27.                   System.out.println("string:" + e);
  28.                   e.printStackTrace(); //jvm 默认的异常处理机制就是调用异常对象的这个方法。
  29.                   System.out.println("负数角标异常!!!");
  30.             } catch(Exception e){//Exception的catch放在最下面,先处理有针对性的异常
  31.                   System.out.println(e);
  32.             }
  33.             System.out.println("over" );
  34.       }
  35. }
复制代码
    运行结果:



    异常处理的原则:
    1. 函数内容如果抛出需要检测的异常,那么函数上必须要声明。
        否则,必须在函数内用try/catch捕捉,否则编译失败。


    2. 如果调用到了声明异常的函数,要么try/catch,要么throws,否则编译失败。


    3. 什么时候catch,什么时候throws呢?
        功能内容可以解决,用catch。
        解决不了,用throws告诉调用者,由调用者解决。


    4. 一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性处理。
       内部有几个需要检测的异常,就抛几个异常,抛出几个,就catch几个。


    示例:
  1. class Demo{
  2.        public int show(int index) throws ArrayIndexOutOfBoundsException{
  3.              if(index < 0)
  4.                    throw new ArrayIndexOutOfBoundsException("越界啦!");
  5.              int[] arr = new int[3];
  6.              return arr[index];
  7.        }
  8. }

  9. class ExceptionDemo{
  10.        public static void main(String[] args){
  11.             Demo d = new Demo();
  12.             try{
  13.                   int num = d.show(-3);
  14.                   System.out.println("num = " + num);
  15.              } catch(ArrayIndexOutOfBoundsException e){
  16.                   System.out.println(e.toString());
  17.                   System.exit(0);//退出jvm
  18.              } finally{//通常用于关闭(释放)资源
  19.                   System.out.println("finally");//由于前面执行了System.exit(0);,故不会执行此语句。
  20.              }
  21.             System.out.println("over");
  22.       }
  23. }
复制代码
   运行结果:



    try catch finally 代码块组合特点:
    1. try catch finally
    2. try catch(多个):当没有资源需要释放时,可以不用定义finally。
    3. try finally:异常无法直接catch处理,但是资源必须关闭。


    示例:
  1. void show() throws Exception{
  2.      try{
  3.           //开启资源
  4.           throw new Exception();
  5.       }finally{
  6.           //关闭资源
  7.       }
  8. }
复制代码

    异常综合案例:
  1. /*
  2. 毕老师用电脑上课。

  3. 问题领域中涉及两个对象。
  4. 毕老师,电脑。

  5. 分析其中的问题。
  6. 比如电脑蓝屏,冒烟等。
  7. */
  8. class LanPingException extends Exception{
  9.       LanPingException(String msg){
  10.              super(msg);
  11.       }
  12. }

  13. class MaoYanException extends Exception{
  14.       MaoYanException(String msg){
  15.              super(msg);
  16.       }
  17. }

  18. class NoPlanException extends Exception{
  19.       NoPlanException(String msg){
  20.              super(msg);
  21.       }
  22. }

  23. class Computer{
  24.        private int state = 1;//0 2
  25.        public void run() throws LanPingException,MaoYanException{
  26.              if(state == 1)
  27.                    throw new LanPingException("电脑蓝屏啦!");
  28.              if(state == 2)
  29.                    throw new MaoYanException("电脑冒烟啦!");
  30.              System. out.println("电脑运行");
  31.        }
  32.        public void reset(){
  33.             state = 0;
  34.             System.out.println("电脑重启");
  35.        }
  36. }

  37. class Teacher{
  38.        private String name ;
  39.        private Computer comp ;

  40.        Teacher(String name){
  41.              this.name = name;
  42.              comp = new Computer();
  43.        }

  44.        public void prelect() throws NoPlanException{
  45.              try{
  46.                   comp.run();
  47.                   System. out.println(name + "讲课");
  48.              } catch(LanPingException e){
  49.                   System.out.println(e.toString());
  50.                   comp.reset();
  51.                   prelect();
  52.              } catch(MaoYanException e){
  53.                   System. out.println(e.toString());
  54.                   test();
  55.                    //可以对电脑进行维修
  56.                    throw new NoPlanException("课时进度无法完成,原因:" + e.getMessage());
  57.              }
  58.        }
  59.        public void test(){
  60.             System.out.println("大家练习");
  61.        }
  62. }

  63. class ExceptionDemo{
  64.        public static void main(String[] args){
  65.             Teacher t = new Teacher("毕老师");
  66.              try{
  67.                   t.prelect();
  68.              } catch(NoPlanException e){
  69.                   System.out.println(e.toString() + "......." );
  70.                   System.out.println("换人");
  71.              }
  72.        }
  73. }
复制代码
   运行结果:



    异常的注意事项:   
    1. RuntimeException以及其子类如果在函数中被throw抛出,可以不用在函数上声明。
    2. 子类在覆盖父类方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类。
    3. 如果父类抛出多个异常,那么子类只能抛出父类异常的子集。
    简单说:子类覆盖父类只能抛出父类的异常或者子类的子集。


    P.S.

    如果父类的方法没有抛出异常,那么子类覆盖时绝对不能抛,就只能try。

4.11 Object类

    Object:所有类的根类。
    Object是不断抽取而来,具备着所有对象都具备的共性内容。

    示例:
  1. class Person{
  2.       private int age ;
  3.       Person(int age){
  4.              this.age = age;
  5.       }
  6. }

  7. class Demo{
  8. }

  9. class ObjectDemo{
  10.        public static void main(String[] args){
  11.             Person p1 = new Person(20);
  12.             Person p2 = new Person(20);
  13.             Person p3 = p1;
  14.       
  15.             Demo d = new Demo();

  16.             System. out.println(p1 == p2);//false
  17.             System. out.println(p1.equals(p2));//false
  18.             System. out.println(p1.equals(p3));//true
  19.             System. out.println(p1.equals(d));//false
  20.       }
  21. }
复制代码
   运行结果:


    P.S.
    ==以及Object类的equals方法默认都是根据对象的哈希值判断两个对象是否相等。
    可以通过覆盖Object的equals方法来重写比较规则。

    示例:
  1. class Person{
  2.        private int age ;
  3.        Person( int age){
  4.              this.age = age;
  5.        }
  6.        //比较Person的年龄,是否是同龄人
  7.        //一般都会覆盖此方法,根据对象的特有内容,建立判断对象是否相同的依据。
  8.        public boolean equals(Object obj){
  9.              if(!(obj instanceof Person))
  10.                    throw new ClassCastException("类型错误");
  11.              Person p = (Person)obj;
  12.              return this .age == p.age;
  13.       }
  14. }

  15. class ObjectDemo{
  16.        public static void main(String[] args){
  17.             Person p1 = new Person(20);
  18.             Person p2 = new Person(20);

  19.             System. out.println(p1.equals(p2));
  20.       }
  21. }
复制代码
   运行结果:


    Object类的toString方法默认返回的内容是“对象所属的类名+@+对象的哈希值(十六进制)”。

    示例:
  1. class Person{
  2.       private int age ;
  3.       Person(int age){
  4.              this.age = age;
  5.       }
  6.       public int hashCode(){
  7.              return age ;
  8.       }
  9. }

  10. class ObjectDemo{
  11.        public static void main(String[] args){
  12.             Person p1 = new Person(20);

  13.             System. out.println(p1);
  14.             System. out.println(p1.getClass().getName() + " $ " + Integer.toHexString(p1.hashCode()));
  15.       }
  16. }
复制代码
   运行结果:



~END~



~爱上海,爱黑马~



点评

赞一个!  发表于 2015-6-5 11:47

50 个回复

倒序浏览
给力啊,这笔记做的细致
回复 使用道具 举报
学习了...
回复 使用道具 举报
顶!顶!顶!顶!顶!顶!
回复 使用道具 举报
顶!顶!顶!顶!顶!顶!
回复 使用道具 举报
:victory::victory::victory:好深刻啊!
回复 使用道具 举报
太详细了
回复 使用道具 举报
异常一直都看的不是很明白,什么时候需要,什么时候不需要。
回复 使用道具 举报
加油,黑马。小板凳,等更新
回复 使用道具 举报
学习中 加油
回复 使用道具 举报
详细!顶一下!!
回复 使用道具 举报
阳哥,辛苦了!
回复 使用道具 举报
进行中  加油  
回复 使用道具 举报
sanmy_lin 来自手机 中级黑马 2015-6-10 12:27:01
14#
看看,应该挺不错的:lol
回复 使用道具 举报
给力,还以为找不到呢,还是被我找到了
回复 使用道具 举报
ARD 初级黑马 2015-6-10 19:57:21
16#
回帖有分加吗???
回复 使用道具 举报
赞。。。。
回复 使用道具 举报
好深刻啊!
回复 使用道具 举报
复制 粘贴 好好研究研究
回复 使用道具 举报
给力,还以为找不到呢,还是被我找到了
回复 使用道具 举报
123下一页
您需要登录后才可以回帖 登录 | 加入黑马