第3章 面向对象 - 异常

优质
小牛编辑
125浏览
2023-12-01

typora-copy-images-to: img

尽管人人希望自己身体健康,处理的事情都能顺利进行,但在实际生活中总会遇到各种状况,比如感冒发烧,工作时电脑蓝屏、死机等。同样,在程序运行的过程中,也会发生各种非正常状况,比如程序运行时磁盘空间不足、网络连接中断、被装载的类不存在等。针对这种情况,在Java语言中,引入了异常,以异常类的形式对这些非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理。

异常的体系

1491277295296

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

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

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

Error类称为错误类,它表示Java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠修改程序本身是不能恢复执行的。举一个生活中的例子,在盖楼的过程中因偷工减料,导致大楼坍塌,这就相当于一个Error。使用java命令去运行一个不存在的类就会出现Error错误。

Exception类称为异常类,它表示程序本身可以处理的错误,在开发Java程序中进行的异常处理,都是针对Exception类及其子类。在Exception类的众多子类中有一个特殊的RuntimeException类,该类及其子类用于表示运行时异常,除了此类,Exception类下所有其他的子类都用于表示编译时异常。本节主要针对Exception类及其子类进行讲解。

Throwable:无论是error,还是异常、问题,问题发生就应该可以抛出,让调用者知道并处理。

1500705144464

该体系的特点就在于Throwable及其所有的子类都具有可抛性。

可抛性到底指的是什么呢?怎么体现可抛性呢?

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

  1. 一般不可处理的:Error

    特点:是由jvm抛出的严重性问题。

    这种问题发生,一般不针对性处理,直接修改程序。

  2. 可以处理的:Exception

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

常见异常

异常说明
IndexOutOfBoundsException角标越界异常
NullPointerException空指针异常
ConcurrentModificationException并发修改异常
ClassCastException类型转换异常
UnsupportedOperationException不支持操作异常
NullPointerException没有元素异常
IllegalArgumentException非法参数异常
IllegalAccessException非法的访问异常

Throwable常用方法

方法声明功能描述
getMessage()获取异常信息,返回字符串。
toString()获取异常类名和异常信息,返回字符串。
printStackTrace()获取异常类名和异常信息,以及异常出现在程序中的位置,返回值void。
printStackTrace(PrintStreams)通常用该方法将异常内容保存在日志文件中,以便查阅。

示例:

  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("数组的角标越界:" +
  8. index);
  9. }
  10. return arr[index];
  11. }
  12. }
  13. class ExceptionDemo{
  14. public static void main(String[] args){
  15. int[] arr = new int[3];
  16. Demo.method(arr,30);
  17. }
  18. }

运行结果:

1491276104173

自定义异常

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

注意事项:

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

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

示例:

  1. Class DemoException extends Exception
  2. {
  3. DemoException(Stringmessage)
  4. {
  5. super(message);
  6. }
  7. }

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

自定义类继承Exception,作为基类

  1. public class HMException extends Exception {
  2. public HMException() {
  3. super();
  4. // TODO Auto-generated constructor stub
  5. }
  6. public HMException(String detailMessage, Throwable throwable) {
  7. super(detailMessage, throwable);
  8. // TODO Auto-generated constructor stub
  9. }
  10. public HMException(String detailMessage) {
  11. super(detailMessage);
  12. // TODO Auto-generated constructor stub
  13. }
  14. public HMException(Throwable throwable) {
  15. super(throwable);
  16. // TODO Auto-generated constructor stub
  17. }
  18. }

子类

  1. public class HMAException extends HMException {
  2. }
  3. public class HMBException extends HMException {
  4. }
  5. public class HMCException extends HMException {
  6. }
  7. public class HMDException extends HMException {
  8. }

ExceptionHandler异常处理器

  1. public class ExceptionHandler {
  2. /**
  3. * 根据不同的HMException给用户具体的提示
  4. * @param e
  5. */
  6. public static void toastByHMException(Context context, HMException e) {
  7. int errCode = 0;
  8. // errCode 具体化
  9. if (e instanceof HMAException) {
  10. errCode = 1;
  11. } else if (e instanceof HMBException) {
  12. errCode = 2;
  13. } else if (e instanceof HMCException) {
  14. errCode = 3;
  15. } else if (e instanceof HMDException) {
  16. errCode = 4;
  17. }
  18. // 根据不同的errcode给用户做提示
  19. toastByErrCode(context, errCode);
  20. }
  21. private static void toastByErrCode(Context context, int errCode) {
  22. String content = "";
  23. switch (errCode) {
  24. case 1:
  25. content = "程序出现了HMAException";
  26. break;
  27. case 2:
  28. content = "程序出现了HMBException";
  29. break;
  30. case 3:
  31. content = "程序出现了HMCException";
  32. break;
  33. case 4:
  34. content = "程序出现了HMDException";
  35. break;
  36. default:
  37. break;
  38. }
  39. Toast.makeText(context, content, 0).show();
  40. }
  41. }

HMApi

  1. public class HMApi {
  2. public void method1() throws HMException {
  3. // 模拟,某一个时刻出现了HMAException
  4. throw new HMAException();
  5. }
  6. public void method2() throws HMException {
  7. // 模拟,某一个时刻出现了HMBException
  8. throw new HMBException();
  9. }
  10. public void method3() throws HMException {
  11. // 模拟,某一个时刻出现了HMCException
  12. throw new HMCException();
  13. }
  14. public void method4() throws HMException {
  15. // 模拟,某一个时刻出现了HMDException
  16. throw new HMDException();
  17. }
  18. }

MainActivity.class,使用自定义异常

  1. public class MainActivity extends Activity {
  2. private HMApi mApi;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_main);
  7. mApi = new HMApi();
  8. }
  9. public void method1(View v) {
  10. try {
  11. mApi.method1();
  12. } catch (HMException e) {
  13. e.printStackTrace();
  14. ExceptionHandler.toastByHMException(MainActivity.this, e);
  15. }
  16. }
  17. public void method2(View v) {
  18. try {
  19. mApi.method2();
  20. } catch (HMException e) {
  21. e.printStackTrace();
  22. ExceptionHandler.toastByHMException(MainActivity.this, e);
  23. }
  24. }
  25. public void method3(View v) {
  26. try {
  27. mApi.method3();
  28. } catch (HMException e) {
  29. e.printStackTrace();
  30. ExceptionHandler.toastByHMException(MainActivity.this, e);
  31. }
  32. }
  33. public void method4(View v) {
  34. try {
  35. mApi.method4();
  36. } catch (HMException e) {
  37. e.printStackTrace();
  38. ExceptionHandler.toastByHMException(MainActivity.this, e);
  39. }
  40. }
  41. }

throws和throw的区别

  1. throws用于标识函数暴露出的异常类,并且可以抛出多个,用逗号分隔。throw用于抛出异常对象

  2. thorws用在函数上,后面跟异常类名。throw用在函数内,后面跟异常对象。

定义功能方法时,需要把出现的问题暴露出来让调用者去处理,那么就通过throws在函数上标识。

在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。

示例:

  1. class FuShuIndexException extends Exception {
  2. FuShuIndexException() {
  3. }
  4. FuShuIndexException(String msg) {
  5. super(msg);
  6. }
  7. }
  8. class Demo {
  9. public static int method(int[] arr, int index) throws FuShuIndexException {
  10. if (index < 0) {
  11. throw new FuShuIndexException ("数组的角标是负数啦!");
  12. }
  13. return arr[index];
  14. }
  15. }
  16. class ExceptionDemo {
  17. public static void main(String[] args) throws FuShuIndexException {
  18. int[] arr = new int[3];
  19. Demo.method(arr, -30);
  20. }
  21. }

运行结果:

1491276277598

异常的分类:

运行时异常和编译时异常

在实际开发中,经常会在程序编译时产生一些异常,而这些异常必须要进行处理,这种异常被称为编译时异常,也称为checked异常。另外还有一种异常是在程序运行时产生的,这种异常即使不编写异常处理代码,依然可以通过编译,因此被称为运行时异常,也称为unchecked异常。

1.编译时异常

在Java中,Exception类中除了RuntimeException类及其子类都是编译时异常。编译时异常的特点是Java编译器会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。处理编译时期的异常有两种方式:

  • 使用try…catch语句对异常进行捕获
  • 使用throws关键字声明抛出异常,调用者对其处理。

2.运行时异常

RuntimeException类及其子类都是运行时异常。运行时异常的特点是Java编译器不会对其进行检查,也就是说,当程序中出现这类异常时,即使没有使用try..catch语句捕获或使用throws关键字声明抛出,程序也能编译通过。运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复。比如通过数组的角标访问数组的元素时,如果超过了数组的最大角标,就会发生运行时异常,代码如下所示:

1500705286982

上面代码中,由于数组arr的length为5,最大角标应为4,当使用arr[6]访问数组中的元素就会发生数组角标越界的异常。

编译时被检测异常

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

编译时不检测异常(运行时异常)

就是Exception中的RuntimeException和其子类。这种问题的发生,无法让功能继续,运算无法运行,更多是因为调用的原因导致的或者引发了内部状态的改变导致的。

那么这种问题一般不处理,直接编译通过,在运行时,让调用者调用时的程序强制停止,让调用者对代码进行调整。

所以自定义异常时,要么继承Exception,要么继承RuntimeException。

示例:

  1. class FuShuIndexException extends RuntimeException {
  2. FuShuIndexException() {
  3. }
  4. FuShuIndexException(String msg) {
  5. super(msg);
  6. }
  7. }
  8. class Demo {
  9. public static int method(int[] arr, int index) {
  10. // RuntimeException没有必要用throws抛出,并不是必须要处理
  11. if (index < 0) {
  12. throw new FuShuIndexException("数组的角标是负数啦!");
  13. }
  14. return arr[index];
  15. }
  16. }

运行结果:

1491276429985

注意事项:

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

异常处理的捕捉形式

可以对异常进行针对性处理的方式。具体格式是:

  1. try{
  2. //需要被检测异常的代码。
  3. }
  4. catch(异常类 变量) //该变量用于接收发生的异常对象
  5. {
  6. //处理异常的代码。
  7. }
  8. finally{
  9. //一定会执行的代码;
  10. }

注意事项:

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
  9. NullPointerException,FuShuIndexException{
  10. if(arr == null)
  11. throw new NullPointerException("没有任何数组实体");
  12. if(index < 0){
  13. throw new FuShuIndexException("数组的角标是负数啦!");
  14. }
  15. return arr[index];
  16. }
  17. }
  18. class ExceptionDemo{
  19. public static void main(String[] args){
  20. int[] arr = new int[3];
  21. try{
  22. int num = Demo.method(arr,-30);
  23. System.out.println("num:" + num);
  24. } catch(NullPointerException e){
  25. System.out.println(e);
  26. } catch(FuShuIndexException e){
  27. System. out.println("message:" + e.getMessage());
  28. System.out.println("string:" + e);
  29. e.printStackTrace(); //jvm 默认的异常处理机制就是调用异常对象的这个方法。
  30. System.out.println("负数角标异常!!!");
  31. } catch(Exception e){//Exception的catch放在最下面,先处理有针对性的异常
  32. System.out.println(e);
  33. }
  34. System.out.println("over" );
  35. }
  36. }

运行结果:

1491276565803

异常处理的原则

  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. }

运行结果:

1491276648860

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. }

运行结果:

1491276689148

异常的注意事项

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

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

异常常见问题

1. try{ }里有一个return x语句,那么紧跟在这个try后的finally { }里的code会不会被执行,什么时候被执行,在return前还是后?

在return中间执行,return x其实是先执行了返回值计算,并把计算结果的地址保存在一个临时的局部变量中,然后开始执行finally子句,finally执行完毕后,再从先前的临时变量中取得返回地址,返回方法的最终结果。根据这样的处理方式,当我们试图在finally子句中再行改变x的值时,已经不会对方法的返回结果造成影响。

return并不是让函数马上返回,而是return语句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行finally语句后才真正开始返回

2. 运行时异常runtime exception与一般异常checked exception有何异同?

对于检查异常,编译器强制要求我们去try catch,否则编译不通过;运行时异常我们可以不处理。这样的异常由虚拟机接管。出现运行时异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果不对运行时异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止

异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常

UncaughtExceptionHandler

UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告,我们可以实现UncaughtExceptionHandler类的uncaughtException方法,该方法的参数为发生异常的线程和异常信息,我们可以在该类中自己处理异常,例如上报服务器或者记录异常等,也可以交由系统的异常处理机制去处理。

示例代码:

  1. package com.github.news.base;
  2. import android.content.Context;
  3. import android.content.pm.PackageInfo;
  4. import android.content.pm.PackageManager;
  5. import android.os.Build;
  6. import android.os.Environment;
  7. import android.os.Looper;
  8. import android.util.Log;
  9. import java.io.File;
  10. import java.io.FileOutputStream;
  11. import java.io.PrintWriter;
  12. import java.io.StringWriter;
  13. import java.io.Writer;
  14. import java.lang.reflect.Field;
  15. import java.text.DateFormat;
  16. import java.text.SimpleDateFormat;
  17. import java.util.Date;
  18. import java.util.HashMap;
  19. import java.util.Locale;
  20. import java.util.Map;
  21. /**
  22. * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告
  23. */
  24. public class CrashHandler implements Thread.UncaughtExceptionHandler {
  25. public static final String TAG = CrashHandler.class.getSimpleName();
  26. //系统默认的UncaughtException处理类
  27. private Thread.UncaughtExceptionHandler mDefaultHandler;
  28. //CrashHandler实例
  29. private static CrashHandler INSTANCE = new CrashHandler();
  30. //程序的Context对象
  31. private Context mContext;
  32. //用来存储设备信息和异常信息
  33. private Map<String, String> infos = new HashMap<String, String>();
  34. //用于格式化日期,作为日志文件名的一部分
  35. private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.CHINA);
  36. /**
  37. * 保证只有一个CrashHandler实例
  38. */
  39. private CrashHandler() {
  40. }
  41. /**
  42. * 获取CrashHandler实例 ,单例模式
  43. */
  44. public static CrashHandler getInstance() {
  45. return INSTANCE;
  46. }
  47. /**
  48. * 初始化
  49. *
  50. * @param context
  51. */
  52. public void init(Context context) {
  53. mContext = context;
  54. //获取系统默认的UncaughtException处理器
  55. mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
  56. //设置该CrashHandler为程序的默认处理器
  57. Thread.setDefaultUncaughtExceptionHandler(this);
  58. }
  59. /**
  60. * 当UncaughtException发生时会转入该函数来处理
  61. */
  62. @Override
  63. public void uncaughtException(Thread thread, Throwable ex) {
  64. if (!handleException(ex) && mDefaultHandler != null) {
  65. //如果用户没有处理则让系统默认的异常处理器来处理
  66. mDefaultHandler.uncaughtException(thread, ex);
  67. } else {
  68. try {
  69. Thread.sleep(3000);
  70. } catch (InterruptedException e) {
  71. Log.e(TAG, "error : ", e);
  72. }
  73. mDefaultHandler.uncaughtException(thread, ex);
  74. // 退出程序
  75. // android.os.Process.killProcess(android.os.Process.myPid());
  76. // System.exit(1);
  77. }
  78. }
  79. /**
  80. * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
  81. *
  82. * @param ex
  83. * @return true:如果处理了该异常信息;否则返回false.
  84. */
  85. private boolean handleException(Throwable ex) {
  86. if (ex == null) {
  87. return false;
  88. }
  89. //使用Toast来显示异常信息
  90. new Thread() {
  91. @Override
  92. public void run() {
  93. Looper.prepare();
  94. // Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show();
  95. Looper.loop();
  96. }
  97. }.start();
  98. //收集设备参数信息
  99. collectDeviceInfo(mContext);
  100. //保存日志文件
  101. Log.i(TAG, "ex:" + ex.toString() + "--" + ex.getLocalizedMessage());
  102. saveCrashInfo2File(ex);
  103. return true;
  104. }
  105. /**
  106. * 收集设备参数信息
  107. *
  108. * @param ctx
  109. */
  110. public void collectDeviceInfo(Context ctx) {
  111. try {
  112. PackageManager pm = ctx.getPackageManager();
  113. PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
  114. if (pi != null) {
  115. String versionName = pi.versionName == null ? "null" : pi.versionName;
  116. String versionCode = pi.versionCode + "";
  117. infos.put("versionName", versionName);
  118. infos.put("versionCode", versionCode);
  119. }
  120. } catch (PackageManager.NameNotFoundException e) {
  121. Log.e(TAG, "an error occured when collect package info", e);
  122. }
  123. Field[] fields = Build.class.getDeclaredFields();
  124. for (Field field : fields) {
  125. try {
  126. field.setAccessible(true);
  127. infos.put(field.getName(), field.get(null).toString());
  128. // Log.d(TAG, field.getName() + " : " + field.get(null));
  129. } catch (Exception e) {
  130. Log.e(TAG, "an error occured when collect crash info", e);
  131. }
  132. }
  133. }
  134. /**
  135. * 保存错误信息到文件中
  136. *
  137. * @param ex
  138. * @return 返回文件名称, 便于将文件传送到服务器
  139. */
  140. private String saveCrashInfo2File(Throwable ex) {
  141. StringBuffer sb = new StringBuffer();
  142. // for (Map.Entry<String, String> entry : infos.entrySet()) {
  143. // String key = entry.getKey();
  144. // String value = entry.getValue();
  145. // sb.append(key + "=" + value + "\n");
  146. // }
  147. Writer writer = new StringWriter();
  148. PrintWriter printWriter = new PrintWriter(writer);
  149. ex.printStackTrace(printWriter);
  150. Throwable cause = ex.getCause();
  151. while (cause != null) {
  152. Log.i(TAG, "cause:" + cause.toString() + "--");
  153. cause.printStackTrace(printWriter);
  154. cause = cause.getCause();
  155. }
  156. printWriter.close();
  157. String result = writer.toString();
  158. Log.i(TAG, "result:" + result);
  159. sb.append(result);
  160. try {
  161. long timestamp = System.currentTimeMillis();
  162. String time = formatter.format(new Date());
  163. String fileName = "crash-" + time + "-" + timestamp + ".log";
  164. if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
  165. String path = "/sdcard/crash/";
  166. File dir = new File(path);
  167. if (!dir.exists()) {
  168. dir.mkdirs();
  169. }
  170. FileOutputStream fos = new FileOutputStream(path + fileName);
  171. fos.write(sb.toString().getBytes());
  172. fos.close();
  173. }
  174. return fileName;
  175. } catch (Exception e) {
  176. Log.e(TAG, "an error occured while writing file...", e);
  177. }
  178. return null;
  179. }
  180. }
  1. public class App extends Application {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. // 设置未捕获异常的处理器
  6. CrashHandler.getInstance().init(this);
  7. }
  8. }

Java常见异常及解释

常见 Java 异常解释:(译者注:非技术角度分析。阅读有风险,理解需谨慎)

java.lang说明
ArithmeticException你正在试图使用电脑解决一个自己解决不了的数学问题,请重新阅读你的算术表达式并再次尝试。
ArrayIndexOutOfBoundsException请查看 IndexOutOfBoundsException。不同之处在于这个异常越界的元素不止一个。
ArrayStoreException你已用光了所有数组,需要从数组商店中购买更多的数组。
ClassCastException你需要呆在自己出生的种姓或阶级。Java 不会允许达利特人表现得像刹帝利或者高贵种族的人假装成为工人阶级。为了保持向前兼容,Java 1.0中把Caste误写为Cast保留到了现在。
ClassNotFoundException你似乎创造了自己的类。这也是目前 Java 还未实现的种姓制度,但是 Java 明显使用了巴厘岛的种姓制度。也就是说,如果你是一个武士,也就相当于印度种姓制度中的第三层——吠舍。
CloneNotSupportedException你是一名克隆人。找到你的原型,告诉他你想做什么,然后自杀。
IllegalAccessException你是一个正在运行 Java 程序入室盗窃的小偷,请结束对电脑的盗窃行为,离开房子,然后再试一次。
IllegalArgumentException你试图反对之前的异常。
IllegalMonitorStateException请打开你的电脑屏幕背面。
IllegalStateException你来自一个尚未被联合国承认的国家,也许是库尔德斯坦或者巴勒斯坦。拿到真正的国籍后重新编译你的 Java 代码,然后再试一次。
IllegalThreadStateException你电脑的一颗螺丝上到了错误的螺纹孔里,请联系你的硬盘供应商。
IndexOutOfBoundsException你把食指放在了无法接收的地方,重新放置,再试一次。
InstantiationException不是每件事都会立即发生,请更耐心一点。
InterruptedException告诉你的同事、室友等,当你工作的时候,请勿打扰。
NegativeArraySizeException你创建了一个负数长度的数组。这会丢失信息,长期发展将会毁灭宇宙。不过放宽心,Java 发现了你正在做的事,不要再这么干了。
NoSuchFieldException你正试图去一个不存在的区域游览。如果你试图去参观一个事实上不存在,其实已经是最高机密的飞机场时,也会得到这个异常。我可以给你示例,然后不得不杀了你。
NoSuchMethodException不要使用那个方法!拜托了,就像我们一直做的那样去解决事情吧。
NullPointerException你没有狗。请你先找一只狗,比如一只布烈塔尼獵犬,然后再试一次。
NumberFormatException你正在使用过时的测量单位,比如英寸或者品脱。请转换成国际基本单位。有一个已知的 bug 会导致 Java 抛出这个异常,那就是你太矮了或者太高了。
RuntimeException你不能跑得足够快,可能因为你太胖了。关掉你的电脑,出门锻炼吧。
SecurityException你已被认为是国家安全的一个威胁。请你呆在原地别动,然后等着警察来并带你走。
StringIndexOutOfBoundsException你的内裤和这个地方格格不入。换掉它们,再试一次。另外如果你根本不穿任何内裤,也会得到这个异常。
UnsupportedOperationException因为一些原因,你正试图做一个在道德上不被 Java 支持的手术。包括不必要的截肢,例如割包皮。请停止滥用你的身体,不要移除你的孩子,该死的!
java.util说明
ConcurrentModificationException有人修改了你的 Java 代码。你应该更改密码。
EmptyStackException为了让 Java 工作,你必须在桌子上放一叠 Java 书籍。当然,如果书很厚的话,一本就够了。
MissingResourceException你太穷了,不配使用 Java。换一个更便宜的语言吧(比如 Whitespace、Shakesperre、Cow、Spaghetti 或者 C#)。
NoSuchElementException这里只存在四种元素(地球、水、空气、火)。《第五元素》只是部电影而已。
TooManyListenersException你被太多秘密机构窃听了,SecurityException 马上就到。
java.awt说明
AWTException你正在使用AWT,也就是说你的图形界面会很丑。这个异常只是一个警告可以被忽略。
FontFormatException你的布局很丑陋,或者你选择了一个糟糕的字体,或者太多的字体。请咨询一名专业的设计师。
HeadlessExceptionJava 认为身为一名程序员,你实在是太蠢了。
IllegalComponentStateException你的一个硬件(例如硬盘、CPU、内存)坏掉了。请联系你的硬件供应商。
java.awt.color说明
CMMException你的 CMM 坏掉了,真是见鬼了。我经常烧毁自己的房子,然后去一个新的城市重新开始。
ProfileDataException你的个人档案包含可疑信息。如果你不是一名共产主义者、恐怖分子或者无神论者,请联系 CIA 修正错误。
java.awt.datatransfer说明
MimeTypeParseException你的哑剧(Mime)糟透了,没人能够理解你到底想表达什么。尝试一些更简单的事情吧,比如迎风散步,或者被困在一个看不见的盒子里。
UnsupportedFlavorException你正试图使用一种 Java 不知道的香料。大部分人似乎只知道使用香草和樱桃。
java.beans说明
IntrospectionException你太内向了,你应该变得外向一些。 别再当一个呆子,出门去见见人吧!
PropertyVetoException你的一部分财产被冻结了。这条信息应该已经告诉你谁干的和原因。如果没看见,你可能也不该询问。
java.io说明
CharConversionException你一直试图焚烧一些不燃物。也可能是因为你试着把自己变成一条鱼,但这不可能发生。
EOFException你得到这条异常是因为你不知道EOF是什么意思。但是,我并不打算告诉你,因为你是一个不学无术的人。
FileNotFoundException一名木匠应该总是知道他的工具放在哪里。
InterruptedIOException你不顾之前的 IOException,一直在使用 IO,然后你的活动就被中断了。
InvalidClassException查看 ClassNotFoundException
InvalidObjectException反对无效,就像他们在法庭上说的一样。
IOExceptionIO 代表输入、输出,并且不得不做收发数据的事。IO 是一个安全问题,不应使用。
NotActiveException这个异常意味着两件事。要么是未激活,需要激活;要么是已激活,需要停止。到开始工作为止,激活与未激活都是随机的。
NotSerializableException你正试图把一部电影改成电视剧。
ObjectStreamException你提出了一连串的反对(Object)意见。提出新的意见前,请限制自己一下,等待法官作出判决。查看 InvalidObjectException
OptionalDataException你似乎认为一些可选数据是必须的。不要让事情变得复杂。
StreamCorruptedException你的数据流被损坏了,这意味着它已经被截包,并在黑市上贩卖。
SyncFailedException你试图与其他人同步你的失败,然后被证明比他人更加失败。去找一些跟你同等水平的人吧。
UnsupportedEncodingException如果你想在网上发送自己的代码,必须与美国国家安全局核对你的加密密匙。如果不这么做,将把你视为恐怖分子,并以适当方式处理。如果你得到这个异常,能跑多快跑多快。
UTFDataFormatExceptionUTF 代表通用传输格式,是一种无论你使用哪种格式都会用到的数据传输方式。你试图通过 UTF 传输错误格式的数据。
WriteAbortedException你需要在程序中的某处写上“aborted”。这通常没什么意义,但你就得这样做。
java.net说明
BindExceptionJava编程和束缚不能混为一谈。
ConnectException你正试图与一个不能连接的事物建立连接。试着连接其他事物吧。也许可以通过一个特殊的连接对象实现你想要的连接。
MalformedURLException你正在制作一个形状错误的壶(例如一个“L”状),或者你有拼写错误的单词“urn”(例如“url”)。
NoRouteToHostException没有通往主机的“道路”,请联系公路管理员。
PortUnreachableException港口必须正确地放置在水边。如果在内陆,它们将会无法接触。
ProtocolException这是一个严重违反规定的结果(例如在你主机上的“puk韓g”)。解决方法很简单:不要那样做!
SocketException你把电脑连接到了错误的电源插座。大部分情况下你不得不寻找其它插座,但一些电脑背部有一个开关,可以设置电源插座类型。
SocketTimeoutException你的电脑连接了一个带计时器的电源插座,并且时间已经走完。只有烙铁和相似的东西才会使用这种插座。
UnknownHostException你的父母没有教过你不要和陌生人说话么?
UnknownServiceException你正试图进入接近一个未知服务。众所周知,未知服务或许是特工组织。
URISyntaxException“You are I”是一个语法错误的句子。将其改为“You are me”,别管那到底啥意思。
java.rmi说明
AccessException你正在使用“Microsoft Access”。请不要这样做。
AlreadyBoundException不管在 java.net.BindException 的描述中是什么状况,RMI 都提供捆绑服务。然而,你不能绑一个已经被捆绑的人。
ConnectException你正试图与一个不能连接的事物建立连接。试着连接其他事物吧。也许可以通过一个特殊的连接对象实现你想要的连接。
ConnectIOException你正试图通过 IO 与另一个不能被连接的事物建立连接。尝试连接其他事物吧。或许你可以通过一个特殊的连接对象实现想要的连接。
MarshalException你的“marshal”出问题了。你应做的事取决于我们正在讨论的是哪种“marshal”。他可以是陆军元帅、警察、消防队员或者只不过是一名普通的司仪。注意这个异常与马绍尔群岛共和国没有任何关系,也称为 RMI。
NoSuchObjectException你正试图使用一个不存在的对象。以爱因斯坦之名,创造它或者不要使用它!
NotBoundException如果你正在使用奴隶,请确认至少有一个人被绑住了。
RemoteException这是一条远程抛出的特殊异常。如果其他人的应用变得不稳定,以致于不能产生一条异常,相反地,你可能会得到这条异常。请找到源头并提醒那位程序员这个错误。
RMISecurityException马绍尔群岛共和国变得不稳定了。如果你住在这儿,你最好离开,直到安全得到保障为止都别回来。如果你住在其他地方,可以无视这个异常。
ServerException第二发球(或者双发失误同样适用)。
ServerRuntimeException只要是网球比赛都很长。当你花太长时间发球时,就会得到这条异常。
StubNotFoundException当你去看电影的时候,你应该一直保留自己的票根。如果不这么做,并且离开了电影院,你就不能重新进去,不得不去买张新票。所以保留你的票根!
UnexpectedException这个异常对你来说应该会成为一个大惊喜。如果发生了,所有事都变成它应该的样子。
UnknownHostException你父母没有教过你不要和陌生人说话吗?
UnmarshalException.你没有完成一名法律工作人员的职责(例如你曾经的法官工作)。注意这个正确的术语是“曾经”(used to)。你已经被解雇(fire)了(如果你是一名消防队员(firefighter),这可真是讽刺啊)。
java.security说明
AccessControlException你失去了对 Microsoft Access 的控制。如果你无法重获控制或者通过其他方式停止程序,你应该尽快切断电脑电源。
DigestException你应该注意自己的食物,消化不良也能变成严重的问题。
GeneralSecurityException在某些地方做一些事情并不安全。如果你有足够的权力,你应该随机入侵一个国家(最好在中东地区)。如果你没有那种权力,至少应该有一把枪。
InvalidAlgorithmParameterException你向一位残疾人用他不能理解的方式解释你的算法。简单一点!
InvalidKeyException这个异常有两种不同的原因:1、你正在使用错误的钥匙。我的建议是在你的钥匙上画不同颜色的小点来帮助你记住哪一把对应哪一个锁。2、 你不能锁住残疾人却不给他们钥匙,如果他们足够聪明发现如何使用钥匙,他们就有自由移动的权利。
InvalidParameterException你使用了蔑视的术语去描述一名残疾人。
KeyException不要尝试不用钥匙就能开锁。
KeyManagementException你遗失了自己的钥匙。很可能忘在办公室(如果你正试图进入你家)或者忘在家里(如果你正试图进入办公室)。
KeyStoreException延续之前 KeyManagementException 的解释就是你的钱包有个洞。
NoSuchAlgorithmException你试图用以前未知的方法解决问题。停止创新吧,用老算法重写一遍。你也可以为自己的想法申请专利,然后等待未来 Java 发布新版本的时候纳入其中。
NoSuchProviderException如果你是一名单亲妈妈,你没法成为家庭主妇。首先,你得为家庭找到一名供养者。
PrivilegedActionException你试图采取一个行动,但是没有得到权限。比如,只有名人才可以做到地从谋杀中逃脱,只有天主教神父和耶和华的高级见证人才能做地猥亵儿童,只有在私人企业担任管理职位的人才能被允许地偷钱。
ProviderException你是一名妇女并试图供养一个家庭。显而易见,你的丈夫不能成为一名“家庭主妇”,所以你得让他供养个家庭。想象一下,Java固执且不肯改变,事情就是这样工作的,解决它。
SignatureException要么你是伪造的其他人的签名,要么是无法接受你的签名。一个签名不能太丑陋、太易读或太大。
UnrecoverableKeyException该死。你把你的钥匙扔进了下水沟。我唯一能安慰你的就是其他人也无法恢复钥匙,所以倒不是必须换掉你的锁。
java.text说明
ParseException你做的没有任何意义,冷静下来,再试一次。