Java(Android) Excpetion

Java Excpetion

       异常指不期而至的各种状况,有可预见的和不可预见的。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。异常包括(Error,Exception)他们都有一个共同的父类Throwable并且实现了Serializable方法。

1. 简单类图

Throwable是所有异常的父类,他包括两个子类Error, Exception。

  • Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止,这个我们一般不用管。
  • Exception(异常):是程序本身可以处理的异常包括RuntimeException, 非运行是异常。

    • RuntimeException(运行时异常,UncheckedException)常见的大概有10中。
             NullPointerException - 空指针引用异常,
             ClassCastException - 类型强制转换异常,
             IllegalArgumentException- 传递非法参数异常,
             ArithmeticException - 算术运算异常,
             ArrayStoreException - 向数组中存放与声明类型不兼容对象异常,
             IndexOutOfBoundsException - 下标越界异常,
             NegativeArraySizeException - 创建一个大小为负数的数组错误异常,
             NumberFormatException - 数字格式异常,
             SecurityException - 安全异常,
             UnsupportedOperationException - 不支持的操作异常,
      这类的异常或者他们的子类异常在编译的过程中是不会去检查的(可以不用try catch语句去捕获异常),出现了这类的异常就是程序员的错误,我们程序员应该在编码的过程中去避免这类的异常,可以通过指针检测,数组越界检测来避免这列的异常发生。

    • 非运行是异常(checked Exception),所有继承自Exception并且不是RuntimeException的异常都是checked Exception,例如IOException,ClassNotFoundException,SQLException。必须对checked Exception作处理,编译器会对此作检查,要么在方法体中声明抛出checked Exception,要么使用catch语句捕获checked Exception进行处理,不然不能通过编译。

(我们一般也会经常创建自己的异常,继承Exception,需要注意的是,唯一有用的就是类型名这个信息,所以不要在异常类的设计上花费精力。)

2. 异常处理(try,catch,finally, throw,throws关键字)

  • 捕获异常(try、catch 和 finally)
    • try 语句不会单独出现,一定会跟catch,或者finally或者两个同时出现。
    • 不管有木有出现异常,finally块中代码都会执行。
    • 一个 try 块可能有多个 catch 块。若如此,则执行第一个匹配块。即Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,不会再执行其他的 catch代码块。
    • 可嵌套 try-catch-finally 结构。
    • 在 try-catch-finally 结构中,可重新抛出异常。
    • 当try和catch中有return时,finally仍然会执行
    • finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的。
    • finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。(文章后面会给出一个例子当finally里面有return语句的时候的情况)
  • 抛出异常:任何Java代码都可以抛出异常,如:自己编写的代码、来自Java开发环境包中代码,或者Java运行时系统。无论是谁,都可以通过Java的throw语句抛出异常。从方法中抛出的任何异常都必须使用throws子句。

    • throws抛出异常:throws语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是Exception异常类型,则该方法被声明为抛出所有的异常。多个异常可使用逗号分割。throws语句的语法格式为:

       methodname throws Exception1,Exception2,..,ExceptionN  
       {  
       } 
      

      例如

      public void throwsFunction() throws Exception{
      }
      

      Throws抛出异常的规则:
      1)如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。
      2)必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误。
      3)仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。
      4)调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

    • throw抛出异常 :throw总是出现在函数体中,用来抛出一个Throwable类型的异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。例如

      if (null == jackrabbitPath.getUrl()) {
      throw new IllegalJackrabbitParameterException("IllegalJackrabbitParameterException ......... url null");
      }
      

3. 异常处理的原则

  • 能处理就早处理,抛出不去还不能处理的就想法消化掉或者转换为RuntimeException处理。因为对于一个应用系统来说,抛出大量异常是有问题的,应该从程序开发角度尽可能的控制异常发生的可能。

  • 对于检查异常,如果不能行之有效的处理,还不如转换为RuntimeException抛出。这样也让上层的代码有选择的余地可处理也可不处理。

  • 对于一个应用系统来说,应该有自己的一套异常处理框架,这样当异常发生时,也能得到统一的处理风格,将优雅的异常信息反馈给用户。

4. 例子(finally块中有返回值)

public class MyClass {

boolean testEx() throws Exception {
    boolean ret = true;
    try {
        ret = testEx1();
    } catch (Exception e) {
        System.out.println("testEx, catch exception");
        ret = false;
        throw e;
    } finally {
        System.out.println("testEx, finally; return value=" + ret);
    }
    return ret;
}

boolean testEx1() throws Exception {
    boolean ret = true;
    try {
        ret = testEx2();
        if (!ret) {
            return false;
        }
        System.out.println("testEx1, at the end of try");
        return ret;
    } catch (Exception e) {
        System.out.println("testEx1, catch exception");
        ret = false;
        throw e;
    } finally {
        System.out.println("testEx1, finally; return value=" + ret);
        return ret;
    }
}

boolean testEx2() throws Exception {
    boolean ret = true;
    try {
        int b = 12;
        int c;
        for (int i = 2; i >= -2; i--) {
            c = b / i;
            System.out.println("i=" + i);
        }
        return true;
    } catch (Exception e) {
        System.out.println("testEx2, catch exception");
        ret = false;
        throw e;
    } finally {
        System.out.println("testEx2, finally; return value=" + ret);
        return ret;
    }
}

public static void main(String[] args) {
    MyClass testException1 = new MyClass();
    try {
        testException1.testEx();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

程序的执行结果

i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, finally; return value=false
testEx, finally; return value=false

注意testEx1 和testEx2函数的finally块中有return语句。当finally语句中有return语句的时候下一级的try语句会正常结束没有异常抛出。相当于异常被终止了。

5. 异常的收集(可以收集所有APK的异常信息或者死机信息,Github上面找到的一个开源库Bugsnag Notifier for Android)

项目地址:Bugsnag Notifier for Android
git上面有介绍具体的用法,简单试了下用起来非常的简单(我用的是免费的测试的),我们可以把一些死机信息,或者一些异常信息发送给他的后台网站,后台网址会帮我们管理这些信息方便我们查询(可以查询到对应的手机信息,内存信息,发送的异常或者死机信息)有兴趣可以试下。

你可能感兴趣的:(java,android,exception,Throwable)