• 异常


    现实生活的病

    现实生活中万物在发展和变化会出现各种各样不正常的现象。

           1:例如:人的成长过程中会生病。

               |——病

                  |——不可治愈(癌症晚期)

                  |——可治愈

                      |——小病自行解决(上火,牙痛)

                      |——去医院(感冒,发烧)

     java异常体系图

    现实生活中的很多病况从面向对象的角度考虑也是一类事物,可以定义为类。      

    java中可以通过类对这一类不正常的现象进行描述,并封装为对象。

    1. java的异常体系包含在java.lang这个包默认不需要导入。
    2. java异常体系

               |——Throwable  (实现类描述java的错误和异常)

                  |——Error (错误)一般不通过代码去处理。

                  |——Exceprion (异常)

                      |——RuntimeException (运行时异常)

                      |——非运行时异常

    常见的Error

    错误原因:内存溢出。需要的内存已经超出了java虚拟机管理的内存范围。

    错误原因:找不到类文件。

    错误(Error):

    它指的是一个合理的应用程序不能截获的严重的问题。大多数都是反常的情况。错误是JVM的一个故障(虽然它可以是任何系统级的服务)。所以,错误是很难处理的,一般的开发人员(当然不是你)是无法处理这些错误的。比如内存溢出.

            3、异常体系图的对应

    Throwable类

    1. toString() 输出该异常的类名。
    2. getMessage() 输出异常的信息,需要通过构造方法传入异常信息(例如病态信息)。
    3. printStackTrace() 打印栈信息。

    人生病:流鼻涕,感冒,呼吸道感染,肺炎。。。最后体现的是肺炎。

        医生要处理需要获知这些信息。从外到里处理。最后找病源

     1 /*
     2  Throwable类
     3 
     4  printStackTrace() 打印栈信息
     5 
     6  肺炎
     7  上呼吸道感染
     8  发烧
     9  流鼻涕感冒
    10  小感冒    
    11  */
    12 class Demo6 {
    13 
    14     public static void main(String[] args) {
    15 
    16         // Throwable able=new Throwable();
    17         Throwable able = new Throwable("想吐。。。");
    18         System.out.println(able.toString()); // 输出该异常的类名
    19         System.out.println(able.getMessage()); // 输出异常的信息
    20         able.printStackTrace(); // 打印栈信息
    21     }
    22 }
    View Code

    程序中的异常处理

    1. 当除数是非0,除法运算完毕,程序继续执行。
    2. 当除数是0,程序发生异常,并且除法运算之后的代码停止运行。因为程序发生异常需要进行处理。
     1 class Demo7 {
     2 
     3     public static void main(String[] args) {
     4         div(2, 0);
     5         System.out.println("over");
     6     }
     7 
     8     public static void div(int x, int y) {
     9         //该行代码的y值可能是0,程序会出现异常并停止
    10         System.out.println(x / y);
    11         System.out.println("除法运算");
    12     }
    13 }
    14 //ArithmeticException 
    View Code

    疑问:  出现异常如何处理?

     自行处理

    1. try{//可能发生异常的代码 }catch(异常类 变量名){//处理}。
    2. 案例除法运算的异常处理。
    3. 如果没有进行try catch处理,出现异常程序就停止。进行处理后,程序会继续执行。
     1 class Demo7 {
     2 
     3     public static void main(String[] args) {
     4         div(2, 0);
     5         System.out.println("over");
     6     }
     7 
     8     public static void div(int x, int y) {
     9 
    10         try {
    11             System.out.println(x / y); // 可能出现异常的语句,放入try中。
    12         } catch (ArithmeticException e) { // 进行异常匹配,
    13              //异常信息
    14             System.out.println(e.toString());
    15                 System.out.println(e.getMessage());    
    16          e.printStackTrace();
    17             System.out.println("除数不能为0");
    18         }
    19         System.out.println("除法运算");
    20     }
    21 }
    View Code

    多个异常

    1. 案例print方法,形参中增加数组。
    2. 在print方法中操作数组会发生新的异常

    ArrayIndexOutOfBoundsException,NullPointerException),如何处理?

    1. 使用将可能发生异常的代码放入try语句中,添加多个catch语句即可。
    2. 可以处理多种异常,但是同时只能处理一种异常。
    3. try中除0异常和数组角标越界同时出现,只会处理一种。
     1 public class Demo8 {
     2 
     3     public static void main(String[] args) {
     4 
     5         System.out.println();
     6         int[] arr = { 1, 2 };
     7         arr = null;
     8 
     9         // print (1, 0, arr);
    10         print (1, 2, arr);
    11 
    12         System.out.println("over");
    13     }    
    14 
    15     public static void print(int x, int y, int[] arr) {
    16 
    17         try {
    18             System.out.println(arr[1]);
    19             System.out.println(x / y);
    20         } catch (ArithmeticException e) {
    21             e.toString();
    22             e.getMessage();
    23             e.printStackTrace();
    24             System.out.println("算术异常。。。");
    25         } catch (ArrayIndexOutOfBoundsException e) {
    26             e.toString();
    27             e.getMessage();
    28             e.printStackTrace();
    29             System.out.println("数组角标越界。。。");
    30         } catch (NullPointerException e) {
    31             e.toString();
    32             e.getMessage();
    33             e.printStackTrace();
    34             System.out.println("空指针异常。。。");
    35         }
    36         System.out.println("函数执行完毕");
    37     }
    38 }
    View Code

    总结

    1. 程序中有多个语句可能发生异常,可以都放在try语句中。并匹配对个catch语句处理。
    2. 如果异常被catch匹配上,接着执行try{}catch(){} 后的语句。没有匹配上程序停止。
    3. try中多个异常同时出现,只会处理第一条出现异常的一句,剩余的异常不再处理。
    4. 使用多态机制处理异常。
      1. 程序中多态语句出现不同异常,出现了多个catch语句。简化处理(相当于急诊)。
      2. 使用多态,使用这些异常的父类进行接收。(父类引用接收子类对象)
      3.  1 public static void div(int x, int y, int[] arr, Father f) {
         2 
         3         try {
         4             System.out.println(arr[1]); // 数组越界
         5             System.out.println(x / y); // 除零
         6             Son s = (Son) f; // 类型转换
         7 
         8         } catch (Exception e) {
         9             e.toString();
        10             e.getMessage();
        11             e.printStackTrace();
        12             System.out.println("出错啦");
        13         }
        14         System.out.println("函数执行完毕");
        15     }
        View Code

        多个catch语句之间的执行顺序。

        1. 是进行顺序执行,从上到下。
        2. 如果多个catch 内的异常有子父类关系。
          1. 子类异常在上,父类在最下。编译通过运行没有问题
          2. 父类异常在上,子类在下,编译不通过。(因为父类可以将子类的异常处理,子类的catch处理不到)。
          3. 多个异常要按照子类和父类顺序进行catch
     1 class Father {
     2 
     3 }
     4 
     5 class Son extends Father {
     6 
     7 }
     8 
     9 public class Demo8 {
    10 
    11     public static void main(String[] args) {
    12 
    13         System.out.println();
    14         int[] arr = { 1, 2 };
    15         arr = null;
    16         Father f = new Father();
    17         div(1, 0, arr, f);
    18         
    19         System.out.println("over");
    20     }
    21 
    22     public static void div(int x, int y, int[] arr, Father f) {
    23 
    24         try {
    25             System.out.println(arr[1]); 
    26             System.out.println(x / y);
    27             Son s = (Son) f;
    28 
    29         } catch (ArithmeticException e) {
    30             e.toString();
    31             e.getMessage();
    32             e.printStackTrace();
    33             System.out.println("算术异常。。。");
    34         } catch (ArrayIndexOutOfBoundsException e) {
    35             e.toString();
    36             e.getMessage();
    37             e.printStackTrace();
    38             System.out.println("数组角标越界。。。");
    39         } catch (NullPointerException e) {
    40             e.toString();
    41             e.getMessage();
    42             e.printStackTrace();
    43             System.out.println("空指针异常。。。");
    44         } catch (Exception e) {
    45             e.toString();
    46             e.getMessage();
    47             e.printStackTrace();
    48             System.out.println("出错啦");
    49         }
    50         System.out.println("函数执行完毕");
    51     }
    52 }
    View Code

    总结

    处理异常应该catch异常具体的子类,可以处理的更具体,不要为了简化代码使用异常的父类。

     

    疑惑:感觉异常没有作用.

     抛出处理

        定义一个功能,进行除法运算例如(div(int x,int y))如果除数为0,进行处理。

    功能内部不想处理,或者处理不了。就抛出使用throw new Exception("除数不能为0"); 进行抛出。抛出后需要在函数上进行声明,告知调用函数者,我有异常,你需要处理如果函数上不进行throws 声明,编译会报错。例如:未报告的异常 java.lang.Exception;必须对其进行捕捉或声明以便抛出throw  new Exception("除数不能为0");

    1 public static void div(int x, int y) throws Exception { // 声明异常,通知方法调用者。
    2 
    3         if (y == 0) {
    4     throw new Exception("除数为0"); // throw关键字后面接受的是具体的异常的对象
    5         }
    6         System.out.println(x / y);
    7         System.out.println("除法运算");
    8     }
    View Code

    main方法中调用除法功能

        调用到了一个可能会出现异常的函数,需要进行处理。

               1:如果调用者没有处理会编译失败。

        如何处理声明了异常的函数。

               1:try{}catch(){}

     1     public static void main(String[] args) {
     2 
     3         try {
     4             div(2, 0);
     5         } catch (Exception e) {
     6             e.printStackTrace();
     7         }
     8         System.out.println("over");
     9 
    10     }
    11 
    12     public static void div(int x, int y) throws Exception { // 声明异常,通知方法调用者。
    13 
    14         if (y == 0) {
    15     throw new Exception("除数为0"); // throw关键字后面接受的是具体的异常的对象
    16         }
    17         System.out.println(x / y);
    18         System.out.println("除法运算");
    19     }
    20 }
    View Code

        2:继续抛出throws 

     1     public static void main(String[] args) {
     2 
     3         try {
     4             div(2, 0);
     5         } catch (Exception e) {
     6             e.printStackTrace();
     7         }
     8         System.out.println("over");
     9 
    10     }
    11 
    12     public static void div(int x, int y) throws Exception { // 声明异常,通知方法调用者。
    13 
    14         if (y == 0) {
    15     throw new Exception("除数为0"); // throw关键字后面接受的是具体的异常的对象
    16         }
    17         System.out.println(x / y);
    18         System.out.println("除法运算");
    19     }
    20 }
    21 
    22                             2:继续抛出throws 
    23 class Demo9 {
    24 
    25     public static void main(String[] args) throws Exception {
    26         div(2, 0);
    27         System.out.println("over");
    28     }
    29 
    30     public static void div(int x, int y) throws Exception { // 声明异常,通知方法调用者。
    31     if (y == 0) {
    32         throw new Exception("除数为0"); // throw关键字后面接受的是具体的异常的对象
    33     }
    34 
    35         System.out.println(x / y);
    36         System.out.println("除法运算");
    37     }
    38 }
    View Code

    throw和throws的区别

    1. 相同:都是用于做异常的抛出处理的。
    2. 不同点:
      1. 使用的位置: throws 使用在函数上,throw使用在函数内
      2. 后面接受的内容的个数不同:
        1. throws 后跟的是异常类,可以跟多个,用逗号隔开。
        2. throw 后跟异常对象。
     1 //throws 处理
     2 public static void main(String[] args) throws InterruptedException {
     3         Object obj = new Object();
     4         obj.wait();
     5 
     6     }
     7 
     8     
     9 public static void main(String[] args) {
    10 
    11         //try catch 处理
    12         Object obj = new Object();
    13         try {
    14             obj.wait();
    15         } catch (InterruptedException e) {
    16             
    17             e.printStackTrace();
    18         }
    19 
    20     }
    View Code

    总结

    1. try语句不能单独存在,可以和catch、finally组成 try...catch...finally、try...catch、try...finally三种结构。
    2. catch语句可以有一个或多个,finally语句最多一个,try、catch、finally这三个关键字均不能单独使用。
    3. try、catch、finally三个代码块中变量的作用域分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。
    4. 多个catch块时候,Java虚拟机会匹配其中一个异常类或其子类,就执行这个catch块,而不会再执行别的catch块。(子类在上,父类在下)。
    5. throw语句后不允许有紧跟其他语句,因为这些没有机会执行。
    6. 如果一个方法调用了另外一个声明抛出异常的方法,那么这个方法要么处理异常,要么声明抛出。

     自定义异常

        问题:现实中会出现新的病,就需要新的描述。

        分析: java的面向对象思想将程序中出现的特有问题进行封装。

        案例:  定义功能模拟凌波登录。(例如:lb(String ip))需要接收ip地址

    1. 当没有ip地址时,需要进行异常处理。

    1. 当ip地址为null是需要throw new Exception("无法获取ip");

                   2. 但Exception是个上层父类,这里应该抛出更具体的子类。

                  3. 可以自定义异常

    1. 自定义描述没有IP地址的异常(NoIpException)。

    1. 和sun的异常体系产生关系。继承Exception类,自定义异常类名也要规范,结尾加上Exception,便于阅读

     1 /*
     2  自定义异常    
     3  */
     4 class NoIpException extends Exception {
     5 
     6     NoIpException() {
     7 
     8     }
     9 
    10     NoIpException(String message) {
    11         super(message);
    12     }
    13 
    14 }
    15 
    16 class Demo10 {
    17 
    18     public static void main(String[] args) throws NoIpException {
    19 
    20         System.out.println();
    21         String ip = "192.168.10.252";
    22         ip = null;
    23         try {
    24             Lb(ip);
    25         } catch (NoIpException e) {
    26             System.out.println("程序结束");
    27         }
    28 
    29     }
    30 
    31     /*
    32      * 
    33      * 凌波教学
    34      */
    35     public static void Lb(String ip) throws NoIpException {
    36         if (ip == null) {
    37             // throw new Exception("没插网线吧,小白");
    38             throw new NoIpException("没插网线吧,小白");
    39         }
    40 
    41         System.out.println("醒醒了,开始上课了。");
    42     }
    43 }
    View Code

    案例:模拟吃饭没带钱的问题

    1. 定义吃饭功能,需要钱。(例如:eat(double money))
    2. 如果钱不够是不能吃放,有异常。
    3. 自定义NoMoneyException();继承Exception 提供有参无参构造,调用父类有参构造初始化。at 方法进行判断,小于10块,throw NoMoneyException("钱不够");
    4. eat 方法进行声明,throws NoMoneyException
    5. 如果钱不够老板要处理。调用者进行处理。try{}catch(){} 。
     1 class NoMoneyException extends Exception {
     2 
     3     NoMoneyException() {
     4 
     5     }
     6 
     7     NoMoneyException(String message) {
     8         super(message);
     9     }
    10 }
    11 
    12 class Demo11 {
    13 
    14     public static void main(String[] args) {
    15 
    16         System.out.println();
    17         try {
    18             eat(0);
    19         } catch (NoMoneyException e) {
    20             System.out.println("跟我干活吧。");
    21         }
    22     }
    23 
    24     
    25     public static void eat(double money) throws NoMoneyException {
    26         if (money < 10) {
    27             throw new NoMoneyException("钱不够");
    28         }
    29         System.out.println("吃桂林米粉");
    30     }
    31 }
    View Code

    运行时异常和非运行时异常

    RuntimeException

    RunntimeException的子类: 

                  ClassCastException

                      多态中,可以使用Instanceof 判断,进行规避

                  ArithmeticException

                      进行if判断,如果除数为0,进行return

                  NullPointerException

                      进行if判断,是否为null

                   ArrayIndexOutOfBoundsException

                      使用数组length属性,避免越界

                  这些异常时可以通过程序员的良好编程习惯进行避免的

    1:遇到运行时异常无需进行处理,直接找到出现问题的代码,进行规避。

                      2:就像人上火一样牙疼一样,找到原因,自行解决即可

                      3:该种异常编译器不会检查程序员是否处理该异常

                      4:如果是运行时异常,那么没有必要在函数上进行声明。

                  6:案例

                      1:除法运算功能(div(int x,int y))

                      2:if判断如果除数为0,throw new ArithmeticException();

                      3:函数声明throws ArithmeticException

                      4:main方法调用div,不进行处理

                      5:编译通过,运行正常

                      6:如果除数为0,报异常,程序停止。

                      7:如果是运行时异常,那么没有必要在函数上进行声明。

    1:Object类中的wait()方法,内部throw了2个异常 IllegalMonitorStateException InterruptedException

    1:只声明了一个(throws) IllegalMonitorStateException是运行是异常没有声明。

     1 class Demo12 {
     2 
     3     public static void main(String[] args){
     4         div(2, 1);
     5     }
     6 
     7     public static void div(int x, int y) {
     8         if (y == 0) {
     9             throw new ArithmeticException();  
    10         }
    11         System.out.println(x / y);
    12     }
    13 }
    View Code

     非运行时异常(受检异常)

    如果出现了非运行时异常必须进行处理throw或者try{}catch(){}处理,否则编译器报错。

               1;IOException  使用要导入包import java.io.IOException;

                      2:ClassNotFoundException

                  2;例如人食物中毒,必须进行处理,要去医院进行处理。

                  3:案例

                      1:定义一测试方法抛出并声明ClassNotFoundException(test())

                      2:main方法调用test

                      3:编译报错

                         1:未报告的异常 java.lang.ClassNotFoundException;必须对其进行捕捉或声明以便抛出

     1 public void isFile(String path){
     2         try
     3         {
     4             /*
     5             根据文件的路径生成一个文件对象,如果根据该路径找不到相应的文件,
     6             则没法生成文件对象。
     7             */
     8             File file = new File(path);
     9             //读取文件的输入流
    10             FileInputStream input = new FileInputStream(file);
    11             //读取文件
    12             input.read();
    13         }
    14         catch (NullPointerException e)
    15         {
    16             System.out.println("读取默认的文件路径..");
    17         }
    18         
    19     }
    View Code

    4:Sun 的API文档中的函数上声明异常,那么该异常是非运行是异常,

    调用者必须处理。

                  5:自定义异常一般情况下声明为非运行时异常

           2:函数的重写和异常

               1:运行时异常

                  1:案例定义Father类,定义功能抛出运行是异常,例如(test() throw

    ClassCastException)

                  2:定义Son类,继承Father类,定义test方法,没有声明异常

                  3:使用多态创建子类对象,调用test方法

                  4:执行子类方法

    1:函数发生了重写,因为是运行时异常,在父类的test方法中,可以声明throws 也可以不声明throws 

     1 class Father {
     2     void test() throws ClassCastException { // 运行时异常
     3         System.out.println("父类");
     4         throw new ClassCastException();
     5     }
     6 }
     7 
     8 class Son extends Father {
     9     void test() {
    10         System.out.println("子类");
    11     }
    12 }
    13 class Demo14 {
    14 
    15     public static void main(String[] args) {
    16         Father f = new Son();
    17         f.test();
    18     }
    19 }
    View Code

    2:非运行时异常

    1:定义父类的test2方法,抛出非运行时异常,例如抛出ClassNotFoundException

                   1:此时父类test2方法必须声明异常,因为是非运行时异常

                  2:Son类定义test2 方法,抛出和父类一样的异常,声明异常

                  3:使用多态创建子类对象,调用test方法,调用test2方法,

    1:声明非运行时异常的方法,在调用时需要处理,所以在main方法调用时throws

                      2:实现了重写,执行子类的test2方法

               3:总结子类重写父类方法可以抛出和父类一样的异常,或

    者不抛出异常。

     1 //  1 子类覆盖父类方法父类方法抛出异常,子类的覆盖方法可以不抛出异常
     2 class Father {
     3     void test() throws ClassNotFoundException { // 非运行时异常
     4         System.out.println("父类");
     5         throw new ClassNotFoundException();
     6     }
     7 }
     8 
     9 class Son extends Father {
    10     void test() {
    11         System.out.println("子类");
    12         // 父类方法有异常,子类没有。
    13     }
    14 }
    15 class Demo14 {
    16 
    17     public static void main(String[] args) throws ClassNotFoundException  {
    18         Father f = new Son();
    19         f.test();
    20 
    21     }
    22 }
    View Code

    4:子类抛出并声明比父类大的异常例如子类test2方法抛出Exception

                      1:编译失败,无法覆盖

                      2:子类不能抛出父类异常的父类。

                      3:总结子类不能抛出比父类的异常更大的异常。

     1 //2:子类覆盖父类方法不能比父类抛出更大异常
     2 class Father {
     3     void test() throws Exception {
     4         // 非运行时异常
     5         System.out.println("父类");
     6         throw new Exception();
     7     }
     8 }
     9 
    10 class Son extends Father {
    11     void test() throws ClassNotFoundException { // 非运行时异常
    12         System.out.println("子类");
    13         throw new ClassNotFoundException();
    14     }
    15 }
    16 class Demo14 {
    17 
    18     public static void main(String[] args) throws Exception {
    19         Father f = new Son();
    20         f.test();
    21 
    22     }
    23 }
    View Code

        3:总结

                  1:子类覆盖父类方法是,父类方法抛出异常,子类的覆盖方法可以不抛

    出异常,或者抛出父类方法的异常,或者该父类方法异常的子类。

                  2:父类方法抛出了多个异常,子类覆盖方法时,只能抛出父类异常的子

                  3:父类没有抛出异常子类不可抛出异常

                      1:子类发生非运行时异常,需要进行try{}catch的(){}处理,不能

    抛出。

                  4:子类不能比父类抛出更多的异常

     finally

           1: 实现方式一:

    try{ // 可能发生异常的代码 } catch( 异常类的类型 e ){ // 当发生指定异常的时候的处理代码 }catch...     

               比较适合用于专门的处理异常的代码,不适合释放资源的代码。

           2:实现方式二:

               try{  } catch(){} finally{ // 释放资源的代码 }

               finally块是程序在正常情况下或异常情况下都会运行的。

               比较适合用于既要处理异常又有资源释放的代码

           3:实现方式三

               try{  }finally{ // 释放资源 }

               比较适合处理的都是运行时异常且有资源释放的代码。

           4:finally:关键字主要用于释放系统资源。

                   1:在处理异常的时候该语句块只能有一个。

               2:无论程序正常还是异常,都执行finally。

           5:finally是否永远都执行?

               1:只有一种情况,但是如果JVM退出了System.exit(0),finally就不执行。

               2:return都不能停止finally的执行过程。

           6:案例使用流

               1:使用FileInputStream加载文件。

                  导包import java.io.FileInputStream;

               2:FileNotFoundException 

                  导入包import java.io.FileNotFoundException;

               3:IOException

                  import java.io.IOException;

     1 public class FinallyDemo {
     2     // 本例子使用finally 关闭系统资源。
     3     public static void main(String[] args) {
     4 
     5         FileInputStream fin = null;
     6         try {
     7             System.out.println("1创建io流可能出现异常");
     8             fin = new FileInputStream("aabc.txt"); // 加载硬盘的文本文件到内存,通过流
     9             // System.out.println(fin);
    10         } catch (FileNotFoundException e) {
    11             System.out.println("2没有找到abc.txt 文件");
    12             System.out.println("3catch 了");
    13             // System.exit(0);
    14             // return;
    15         }
    16         // finally
    17         finally {
    18             System.out.println("4fianlly执行");
    19             if (fin != null) { // 如果流对象为null 流对象就不存在,没有必要关闭资源
    20                 try {
    21                     fin.close();
    22                 } catch (IOException e) {
    23                     e.printStackTrace();
    24                     System.out.println("close 异常");
    25                 }
    26 
    27             }
    28             System.out.println("5finally over");
    29         }
    30         System.out.println("6mainover");
    31     }
    32 }
    33 
    34 // 2:无论程序正常还是异常,都执行finally。 但是遇到System.exit(0); jvm退出。
    35 // finally用于必须执行的代码, try{} catch(){}finally{}
    36 // try{}finally{}
    View Code
  • 相关阅读:
    重启远程windows计算机
    web.xml文件的作用及基本配置
    DB2编码问题而导致连接不上上数据库
    合理使用表空间
    自动做题
    怎么给二年级小学生讲鸡兔同笼问题
    DB2 性能分析工具介绍:Event Monitor 篇(摘自IBM官方)
    delphi 对应 c# 的一些函数及类型的转换方法(从网络摘录)
    DB2 基础: 使用重定向恢复克隆 DB2 数据库(部分从IBM官方网站引用)
    response.setContentType()的作用及MIME参数详解
  • 原文地址:https://www.cnblogs.com/Michael2397/p/5960921.html
Copyright © 2020-2023  润新知