或许大家都试过这样的一种经历:不管是玩手机还是电脑,在运行一个软件的时候,有时候会无端端的崩溃掉。这种情况在就连qq在早期的时候也会发生。当然,不仅是他,就连我们使用的系统,也会有这种情况。比如windows就比较喜欢弹出一个提交错误信息报告,告诉你程序哪里有问题了,要重启。你按下确定键后,他就帮你重新启动,你要是按了其他,他就直接退出了。这要是在平时倒没什么,但是如果你在玩游戏玩到刺激的时候忽然挂掉的话,那才叫心痛啊是吧。当然,没有什么程序是不会出问题的,作为开发者,我们应该做的就是尽力去避免出现bug,以免影响用户对软件的体验度。同时,一旦出现了错误,我们也应该尽快去进行修复,而基于这一原则,就诞生我们今天的主角——java的异常处理。
什么叫异常处理
java中的异常处理是基于面向对象的一种运行态错误处理机制,通过对异常信息的封装实现对用户非法操作、参数设置异常、硬件系统异常,运行时网络状态更换等在运行态中可能出现的异常信息的处理机制。
异常处理机制的体系结构
前面说到异常处理是基于面向对象而实现的,也即是说java把大部分可能存在的异常信息都封装成一个个对应的类了。当然,我们也可以在原有类的基础上进行拓展。这就涉及了异常处理机制的体系结构:
* 继承结构
Throwable
|- Error 系统级错误
|- Exception 可修复的异常
|- 其他Exception
|- RuntimeException
|- NullPointerException
|- ArrayIndexOutOfBoundsException
|- ArithmeticException
|- NumberFormatException
|- ClassCastException
|- InputMismatchException
...
在异常处理机制中,为了方便对异常信息进行跟踪,一般设定异常信息的内容如下:
错误信息:
*)类型名称
*)提示消息
*)行号
案例说明:
package testabstractclass;
import java.io.IOException;
public class Test1 {
public static void main(String[] args) throws IOException{
int i = 1;
i = i/0;
System.out.println(i);
}
}
运行该程序,报错如下:
你看,这是一个用整数去除以0时,系统报出的异常。在这里我们就可以清晰地看到这个异常是什么意思,并且该异常出现的位置都已经显示出来了,如此我们就可以直接在代码中定位到该位置并且对错误进行修改,这就是异常处理机制最大的好处:跟踪错误代码。并且,还有一个比较重要的好处,就是对于一些可修复的程序来说,我们可以直接捕获到这个异常,并且直接修改修复它,从而避免了系统崩溃的发生。同样的例子,我们进行修改如下:
package testabstractclass;
import java.io.IOException;
public class Test1 {
public static void main(String[] args) throws IOException{
int i = 1;
try {
i = i/0;
} catch (Exception e) {
i += 1;
}
System.out.println(i);
}
}
运行结果,你会惊喜地发现,最后打印出来的是2,而不是报错。这就是因为我们在程序中捕获到了这个异常并且做出了相应的修改。那么,由我们的代码便引出了下面的一个问题:
如何捕获异常:
在java中,捕获异常的格式可以简述为下面这样:
try{
可能发生异常的代码块
}catch(可以捕获的异常1){
处理异常1的代码
}catch(可以捕获的异常2){
处理异常2的代码
}finally{
处理完所有异常后一定会执行的代码。
在这里注意的事。如果在这里没有出现异常,最终也会执行这行代码
}
注意,在这里,格式是可以发生变化的,我们可以增加catch块,也可以不需要finally块。但是我们总不能说因为可以省略就可以不说吧,因此在这里便列出了一个相对完善的包含所有异常关键字的格式,它的流程如下:至于其他的格式,你们可以根据这个来参考实现:
如何处理异常的两种方式
在上面的代码中,我们实现了如何检测代码异常以及处理这个异常。但是对于一些异常来说,是难以实际去修复的,那怎么办呢?常见的一个方法是:编写一个异常处理类,当我们捕获到任何异常时,都将其进行统一的处理,比如在软件上线时,我们不可能一个一个用户说:哦,你这里出现了这个问题,我给你修复了,你用我修复的这个吧。要是这样的话,铁定会把开发者给累死啊,怎么办呢?我们就把说有用户出现的错误信息集中发到开发者的邮箱,然后开发者进行修改,测试没问题之后,就对外公布说:我们的版本升级了,更好玩哦,快来更新吧!你看,这就是为什么我们要更新的好处啦。好,下面干货走起,以android中处理错误信息为例,请看:
/**
* 同一处理异常
* @author 明立
*
*/
//Throwable是所有异常的父类,这里使用的技术就是多态了
public static void handleException(Throwable mThrowable){
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
mThrowable.printStackTrace(printWriter);
String throwableinfo = stringWriter.toString();
//isRelease,版本标志符
//true:上线版本
//false:开发版本
if (isRelease) {
//将异常信息发送至服务器,由服务器发邮件给开发者
}else {
//在Log上打印错误信息
}
}
}
当然,还有一种情况,即当我们还没捕获到异常的时候,程序就已经崩溃了,那怎么办,聪明的程序员老大哥们已经想好了处理办法,即重写一个类继承UncaughtExceptionHandler方法捕获异常并提示用户并在两秒后重启应用,这就避免了你崩溃后用户直接把你删掉的结局。干货如下:
/**
* 程序异常crach时处理类(自动重启)
* @author 明立
*
*/
public class CrachHandler implements UncaughtExceptionHandler {
//程序的Application实现类,声明周期为应用创建到应用彻底销毁
private CApplication mApplication;
public CrachHandler(CApplication mApplication) {
super();
new Thread().start();
this.mApplication = mApplication;
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
// 用上面的ExceptionHandle类联网发送错误信息
ExceptionHandle.handleException(throwable);
//出现自动重启
new Thread(){
public void run() {
Looper.prepare();
Toast.makeText(mApplication, "程序出错,自动重启", Toast.LENGTH_SHORT).show();
Looper.loop();
};}.start();
try {
Thread.sleep(2000);
} catch (Exception e) {
ExceptionHandle.handleException(e);
}
//两秒后自动重启软件,用peddingIntent实现
Intent intent = new Intent(mApplication,MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(mApplication, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
AlarmManager alarmManager = (AlarmManager) mApplication.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(alarmManager.RTC, System.currentTimeMillis()+2000, pendingIntent);
mApplication.exit();
}
}
当然,在这里将Android可能有点超纲了,但实际未然,因为我们介绍完java深入知识点之后,就会正式接触到Android开发,而期间在各方面可能都会使用到异常,因此在此粘出来,以来让大家看看Android和Java之间的联系。二来也可以让大家提前掌握这个知识点。而如果说想要深入去理解何为异常处理机制的话,可以参见这篇博客(真的是写得非常详细,极力推荐):
java提高篇-java异常处理
下一篇:Java的多线程实现,敬请期待:
如果对文章有疑问,可在下方评论指出,共同探讨~