zoukankan      html  css  js  c++  java
  • Java基础学习 -- 异常

      当异常发生时,原本要接着执行的代码不再执行,转而让其他部分的代码来处理。如果没有代码负责处理,控制台会报告异常。

      异常出现时的执行机制

      异常机制最大的好处是:清晰地分开了 正常的业务逻辑遇到情况时的处理 代码。(当在业务逻辑中,有多步可能会抛出不同的异常时,异常处理机制的好处更得以体现。如果没有这种机制,也许会通过很多的if...else...来实现异常处理,甚至是多层嵌套的if...else...,这样的代码可读性很差)

      通过例子来理解:

    package exception;
    
    public class ExceptionCatch {
       public static void main(String[] args) {
         try {
           //我们通过抛出异常来抽象真实的业务逻辑,可能某一步会出现异常,这时下面的代码就不再执行,转而到处理代码。
           //执行完处理代码之后不会再回到之前try里没执行完的代码继续执行,而是去往下执行try{}catch{}之后的代码。
    throw new NullPointerException();
                throw new ArrayIndexOutOfBoundsException();
           throw ...                  
    }
    catch(NullPointerException e) {     //异常处理代码 }catch(ArrayIndexOutOfBoundsException e) {
           //异常处理代码
         }catch(Exception e){
           //异常处理代码
     } } }

       -----------------------------------------------------

      捕捉到异常之后怎么处理?

      当catch到异常之后,根据你的业务逻辑来对它进行处理,比如说可以弹出一个窗口来警告用户发生了错误,或者让程序自己重新执行或者终止掉等等。当然,如果现在处理不了这个异常,也可以将它再次抛出。

      处理完异常之后是回不到异常发生的地方继续执行以下的代码了,而是从catch{}后面的代码开始执行。

      一个异常只能被捕捉一次,捕捉之后这个异常就没有了。不可能再次捕捉到。

       -----------------------------------------------------

      自定义异常类的构造器getMessage()方法的使用 :

     1 package exception;
     2 
     3 //注意观察两个异常类构造器的区别。

      /**
      * 推断

      * 第一个异常类是自己定义了一个String变量,在构造的时候是将信息传给了这个变量;
      * 而第二个异常类的构造器是覆盖了父类的构造方法,所以我们猜测,父类Exception里一定有一个String类型的成员变量(这个成员变量同样继承给了MyException子类),
      * 所以在构造的时候利用super()将父类的构造方法取过来,进而将信息传给了父类里的那个String成员变量。
      * 而getMessage()方法也是从父类那里继承来的,进而我们推断:getMessage()方法返回的正是那个String变量。
     * 在第一个异常类的那个从父类继承的String变量并没有被赋值,所以通过getMessage()取到的是null。
      */
     4 class MyException extends Exception {
     5     String msg;
     6     public MyException(String msg) {
     7         this.msg = msg;
     8     }
     9     public void printMsg() {
    10         System.out.println("msg = " + msg);
    11     }
    12 }
    13 
    14 class MyException2 extends Exception {
    15     public MyException2(String s) { 
    16         super(s); 
    17     }
    18 }
    19 
    20 public class E04_ExceptionClass {
    21     public static void main(String args[]) {
    22         try {
    23             throw new MyException("MyException message");
    24         } catch(MyException e) {
    25             e.printMsg();
    26             System.out.println("e.getMessage() = " + e.getMessage()); //输出为null。
    27         }
    28         
    29         try {
    30             throw new MyException2("MyException2 message");
    31         } catch(MyException2 e) {
    32             System.out.println("e.getMessage() = " + e.getMessage());
    33         }
    34     }
    35 }
    36 /*Output:msg = MyException message
    37  *       e.getMessage() = null
    38  *       e.getMessage() = MyException2 message
    39  */

       -----------------------------------------------------

      printStackTrace()方法:堆栈跟踪

      我们知道在程序代码执行的过程中,某个主线程可能会调用其他的代码程序,调用执行之后,回来继续执行主线程。这个过程中就需要堆栈来存储调用时的断点。(因为在嵌套调用的时候会需要存储多个断点,返回的时候再倒序依次返回,这要遵循后进先出的原则。)

      堆栈跟踪便可以看成是对代码调用的跟踪,当异常发生时可以根据该异常的printStackTrace()方法,打印出该异常的整个传递过程

      -----------------------------------------------------

      一个方法里如果会抛出异常,则必须在方法头部声明 throws 异常名 。如果不声明则必须在这个方法里通过 try{}catch{} 将异常处理掉。

      运行时刻的异常,如ArrayIndexOutOfBoundsException,NullPointerException等,不需要在方法头部声明。(Java核心技术里称这些未unchecked Exception,未检查异常。)

      一个方法可以声明多个异常抛出 throws 异常1 , 异常2 ,但是在以后调用该方法时必须有多个catch来捕捉不同的异常。温馨提示:往往在编程时,会把所有可能会有的异常(现在会有的和以后可能会有的)全都声明在方法之后,这是一种习惯。因为在后期在对该方法进行功能扩展时可能会遇到出现这些异常,而当时在声明这些异常之后编译器会提示你将这些异常一一catch,所以这时你只需要填补catch里的处理内容,这会来带一定的便利。

      下面是一个示例:

    package exception;
    
    class OpenException extends Throwable {}
    class CloseException extends Throwable {}
    
    public class c {
        public static int open() {
            return -1;
        }
        
        public static void readFile() throws OpenException,CloseException {
            if(open() == -1) throw new OpenException();
        }
        
        public static void main(String[] args) {
            try {
                readFile();
            } catch (OpenException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (CloseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    }

       -----------------------------------------------------

      异常捕捉时的匹配

    • 子类异常可以被捕捉父类异常的catch捕捉
    • 如果有多个匹配的异常,会按书写的顺序来,顺序里的第一个匹配的catch来捕捉。

      -----------------------------------------------------

      继承关系下异常的声明

    • 覆盖一个方法时,子类方法声明的异常版本不能比父类方法所声明的多。
    • 子类的构造函数中,必须声明父类声明可能抛出的全部异常。
  • 相关阅读:
    CodeVs 1295 N皇后问题
    POJ 3349 Snowflake Snow Snowflakes
    链表API
    Hash API
    CodeVS 1220 数字三角形
    CodeVS 1045 回文数
    CodeVS 1058 合唱队形(DP--最长子序列问题)
    CodeVS 1018 单词接龙(DFS)
    关于图覆盖问题习题BY石家名
    软件测试作业(二)
  • 原文地址:https://www.cnblogs.com/xingyazhao/p/5985817.html
Copyright © 2011-2022 走看看