13 March 2016

java异常天天用,但是你对他了解究竟有多少。俗话说学习不总结,等于没学习。(好吧,我承认是我说的)。 转自:点击查看

##常用异常分类及概念

  • Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。 它的两个子类是Error和Exception;
    • Throwable 包含了其线程创建时线程执行堆栈的快照。
    • 它还包含了给出有关错误更多信息的消息字符串。
    • 最后,它还可以包含 cause(原因):另一个导致此 throwable 抛出的 throwable。它也称为异常链,因为 cause 自身也会有 cause,依此类推,就形成了异常链,每个异常都是由另一个异常引起的。所以程序发生错误的时候,尤其是新手不用紧张,只要日志齐全,通过这个异常链很容易找到程序的错误。
  • Error 是 Throwable 的子类,用于指示合理的应用程序不应该(有些甚至没有能力)试图捕获的严重问题。比如内存溢出之类的异常,
  • Exception 类及其子类是 Throwable 的一种形式,这种异常,一般都需要我们通过程序去捕获处理。

  • RuntimeException 是Exception的一个子类,它在Exception的子类中稍微有点特殊。
    • 首先它是是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。
    • 其次该类及其子类是不许要在程序中捕获的也不用在throws语句中声明,如果有发生这种异常,会自动抛出。
    • 为什么会设计这么一个类呢,涉及这个异常的目的是为了说明,有些错误,发生了,就发生了,不要试图去补救,补救是没有用的。
    • 常见的这类异常有:空指针异常,某排序索引(例如对数组、字符串或向量的排序)超出范围时的异常,数学计算类的异常(比如除数为0)。
  • Exception中除了RuntimeException的其他异常,这类异常需要我们显式的throws或者try cath进行处理,常见的入文件读写异常,数据库连接异常,类查找异常等等。

对比认识Error和Exception

  • Exception:
    • 1.可以是可被控制(checked) 或不可控制的(unchecked)
    • 2.表示一个由程序员导致的错误
    • 3.应该在应用程序级被处理
  • Error:
    • 1.总是不可控制的(unchecked)
    • 2.经常用来用于表示系统错误或低层资源的错误
    • 3.如何可能的话,应该在系统级被捕捉

      RuntimeException和Exception其他子类

  • Checked exception: 这类异常都是Exception的子类 。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。
  • Unchecked exception: 这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是非凡的,它们不能通过client code来试图解决,所以称为Unchecked exception 。

Checked Exception与Runtime Exception 的区别

  • Java里有个很重要的特色是Exception ,也就是说允许程序产生例外状况。而在学Java 的时候,我们也只知道Exception 的写法,却未必真能了解不同种类的Exception 的区别。
  • 首先,您应该知道的是Java 提供了两种Exception 的模式,一种是执行的时候所产生的Exception (Runtime Exception),另外一种则是受控制的Exception (Checked Exception)。
  • 所有的Checked Exception 均从java.lang.Exception 继承而来,而Runtime Exception 则继承java.lang.RuntimeException 或java.lang.Error (实际上java.lang.RuntimeException 的上一层也是java.lang.Exception)。
  • 当我们撰写程序的时候,我们很可能会对选择某种形式的Exception 感到困扰,到底我应该选择Runtime Exception 还是Checked Exception ?
  • 其实,在运作上,我们可以通过Class 的Method 如何产生某个Exception以及某个程序如何处理这个被产生来的Exception 来了解它们之间的差异。首先我们先建立一个Exception

      public class CException extends Exception {  
          public CException() {  
          }  
          
          public CException(String message) {  
              super(message);  
          }  
      }  
    
  • 然后我们撰写一个可能产生 CException 的 Class

    public class TestException {
    public void method1() throws CException {
    throw new CException(“Test Exception”);
    }

      public void method2(String msg) {  
          if (msg == null) {  
              throw new NullPointerException("Message is null");  
          }  
      }  
      
      public void method3() throws CException {  
          method1();  
      }  
      
      // 以下省略  
      // ...     }  
    
  • 在这三个method 中,我们看到了method1 和method2 的程序码内都会产生Exception,但method3 的程序码中(大括号内),并没产生Exception,但在method3 的定义中,暗示了这个method 可能产生CException。
  • 调用method1() 的程序,必须将method1() 包含在try 与catch 中,如:

      public class Runtest {  
          // ....  
          public static void main(String argv[]) {  
              TestException te = new TestException();  
              try {  
                  te.method1();  
              } catch (CException ce) {  
                  // ....  
                  ce.printStackTrace();  
              }  
          }  
          // ...  
      }  
    
  • 虽然包含在try 与catch 中,并不表示这段程序码一定会收到CException,但它的用意在于提醒呼叫者,执行这个method 可能产生的意外,而使用者也必须要能针对这个意外做出相对应的处理方式。
  • 当使用者呼叫method2() 时,并不需要使用try 和catch 将程序码包起来,因为method2 的定义中,并没有throws 任何的Exception ,如:

      public class Runtest  
      {  
      // ....  
      public static void main(String argv[])  
      {  
          
      testException te = new testException();  
          
      // 不会产生 Exception  
      te.method2("Hello");  
          
      // 会产生 Exception  
      te.method2(null);  
      }  
      // ...  
      }  
    
  • 程序在执行的时候,也不见得会真的产生NullPointerException ,这种Exception 叫做runtime exception 也有人称为unchecked exception ,产生Runtime Exception 的method (在这个范例中是method2) 并不需要在宣告method 的时候定义它将会产生哪一种Exception 。
  • 在testException 的method3() 中,我们看到了另外一种状况,也就是method3里呼叫了method1() ,但却没有将method1 包在try 和catch 之间。相反,在method3() 的定义中,它定义了CException,实际上就是如果method3 收到了CException ,它将不处理这个CException ,而将它往外丢。当然,由于method3 的定义中有throws CException ,因此呼叫method3 的程序码也需要有try catch 才行。
  • 因此从程序的运作机制上看,Runtime Exception与Checked Exception 不一样,然而从逻辑上看,Runtime Exception 与Checked Exception 在使用的目的上也不一样。
  • 一般而言,Checked Exception 表示这个Exception 必须要被处理,也就是说程序设计者应该已经知道可能会收到某个Exception(因为要try catch住) ,所以程序设计者应该能针对这些不同的Checked Exception 做出不同的处理。
  • 而Runtime Exception 通常会暗示着程序上的错误,这种错误会导致程序设计者无法处理,而造成程序无法继续执行下去。看看下面的例子:

      String message[] = {"message1", "message2","message3"};
      System.out.println(message[3]);
    
  • 这段程序码在Compile 时并没问题,但在执行时则会出现ArrayIndexOutOfBoundException 的例外,在这种状况下,我们亦无法针对这个Runtime Exception 做出有意义的动作,这就像是我们呼叫了testException 中的method2 ,却引发了它的NullPointerException 一样,在这种状况下,我们必须对程序码进行修改,从而避免这个问题。
  • 因此,实际上我们应该也必须要去抓取所有的Checked Exception,同时最好能在这些Checked Exception 发生的时候做出相对应的处理,好让程序能面对不同的状况。
  • 然而对于Runtime Exception ,有些人建议将它catch 住,然后导向其它地方,让程序继续执行下去,这种作法并非不好,但它会让我们在某些测试工具下认为我们的程序码没有问题,因为我们将Runtime Exception “处理”掉了,事实却不然!譬如很多人的习惯是在程序的进入点后用个大大的try catch 包起来,如:

      public class Runtest1 {  
          public static void main(String argv[]) {  
              try {  
                  // ...  
              } catch (Exception e) {  
              }  
          }  
      }  
    
  • 在这种情况下,我们很可能会不知道发生了什么Exception 或是从哪一行发出的,因此在面对不同的Checked Exception时,我们可已分别去try catch它。而在测试阶段时,如果碰到Runtime Exception ,我们可以让它就这样发生,接着再去修改我们的程序码,让它避免Runtime Exception,否则,我们就应该仔细追究每一个Exception ,直到我们可以确定它不会有Runtime Exception 为止!
  • 对于Checked Exception 与Runtime Exception ,我想应该有不少人会有不同的观点,无论如何,程序先要能执行,这些Exception 才有机会产生。因此,我们可以把这些Exception 当成是Bug ,也可以当成是不同的状况(Checked Exception),或当成是帮助我们除错的工具(Runtime Exception),但前提是我们需要处理这些Exception ,如果不处理,那么问题或状况就会永远留在那里。




Fork me on GitHub