异常
程序中,代码出现错误,程序就会终止运行。
异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。
异常处理是衡量一门语言是否成熟的标准之一,主流的语言 Java、C++、C# 等支持异常处理机制,异常处理机制可以让程序有更好的容错性,使程序代码更健壮(遗憾的是传统的 C 语言却没有异常处理,只能程序通过使用方法的特定返回值来表示异常情况,并且使用 if 语句来判断正常和非正常情况)。
没有一场极致存在的缺点
1:使用方法的返回值来表示异常情况有限,无法穷举所有的异常情况
2:异常流程代码和正常流程代码混合一起,增大了程序的复杂性,可读性差
3:随着系统规模的不断扩大,程序的可维护性极低
针对与上组没有异常机制的缺点,解决方案为:
1:把不同类型的异常情况描述成不同类(称之为异常类)
2:分离异常流程代码和正确流程代码
3:灵活处理异常,如果当前方法处理不了,应该交给调用者来处理
注:Throwable 类是 Java 语言中所有错误或异常的超类。
非正常情况(出现后程序会终端)
Error:表示错误,一般指 JVM 相关的不可修复的错误。如:系统崩溃,内存溢出,JVM 错误等,由 JVM 抛出,我们不需要处理。
几乎所有的子类都是以 Error 作为类名的后缀(但是测试框架的设计者,却把大量的异常类设为 Error)。
Exception:表示异常,指程序中出现不正常的情况,该问题可以修复。几乎所有的子类都是以 Exception 作为类名的后缀。
出现异常可以把异常的简单类名,拷贝到API中查。
1:常见的 Error
StackOverflowError:当应用程序递归太深而发生内存溢出时,抛出该错误。
2:常见的 Exception
1.NullPointerException:空指针异常,一般指当对象为 null 的时候,调用了该对象的方法,字段
2.ArrayIndexOutOfBoundsException:数组的索引越界(小于 0 或者大于等于数组长度)
3.NumberFormatException:数字格式化异常,一般指,把非 0~9 的字符串转换为整数
如果异常出现,会立刻终止程序,所以需要处理异常
1该方法不处理,而是声明抛出,由该方法的调用者来处理(throws)
2在方法中使用try-catch的语句块来处理异常
使用try-catch捕获单个异常,语法如下
try{
编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常等
}
注意:try 和 catch 都不能单独使用,必须连用(try 也可以只和 finally 连用)
获取异常信息 Throwable 类的方法
1、String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因)
2、String toString():获取异常的跟踪栈信息(不使用)
3、void printStackTrace():打印异常的跟踪栈信息并输出到控制台,不需要使用 System.out.println(); 该方法包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用 printStackTrace
注:目前(开发时)在 catch 语句块中,必须写:e.printStackTrace()
目的:查看异常的具体信息,方便调试和修改
使用try-catch捕获多个异常
try{
编写可能会出现异常的代码
}catch(异常类型A e){
//当 try 出现 A 类型的异常,就用该 catch 来捕获处理异常的代码
//记录日志/打印异常信息/继续抛出异常等
}catch(异常类型B e){
//当 try 出现 B 类型的异常,就用该 catch 来捕获处理异常的代码
//记录日志/打印异常信息/继续抛出异常等
}
注:
1.一个 catch 语句,只能捕获一种类型的异常,如果需要捕获多种异常,就得使用多个 catch 语句(JDK1.7 后有强化的catch)。
2.代码在一瞬间只能出现一种类型的异常,只需要一个 catch 捕获,不可能同时出现多个异常。
finally
finally语句块:表示最终都会执行的代码,无论有没有异常。
当在 try 语句块中打开了一些物理资源(磁盘文件/网络连接/数据库连接等)。都得在使用完成之后,最终关闭打开的资源。
finally 的两种语法
1:try...finally:此时没有catch来捕获异常,因为此时根据应用场景会自动抛出异常,不需要自己处理。
2:try...catch...finally:自身需要处理异常,最终还得关闭资源
注:finally 不能单独使用
当只有在try或者catch中调出退出 JVM 的相关方法,此时 finally 才不会执行,否则 finally 永远会执行
System.exit():退出JVM
异常(Exception)的分类:
1、编译时期异常:checked 异常,在编译时期就会检查,如果没有处理异常则编译失败。
2、运行期异常:runtime 异常,在运行时期,检查异常,在编译时期,编译器不会检测运行异常(不报错)。
运行异常:在编译时期,可处理也可以不处理
抛出异常
throw:运用与方法内部,用于给调用者返回一个异常对象,和 return 一样会结束当前方法。
throws:运用与方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常)。
throw语句:运用于方法内部,抛出一个具体的异常现象
throw new 异常类("异常信息");//终止方法
throw:
一般的,当一个方法出现不正常的情况的时候,不知道该方法应该返回什么,此时就一直返回一个错误,在 catch 语句块中继续向上抛出异常。
return 是返回一个值,throw 是返回一个错误,返回给该方法的调用者。
如果每一个方法都放弃处理异常都直接通过 throws 声明抛出,最后异常会跑到main方法,如果此时 main 方法不处理,继续抛出给 JVM 底层的处理机制就是打印异常的跟踪栈信息。
runtime 异常,默认就是这种处理方式。
自定义异常类:
Java 中有不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是 SUN 没有定义好的,此时需要根据自己业务的异常情况来定义异常类。
异常类如何定义:
方式1:自定义一个受检查的异常类:自定义类,并继承于 java.lang.Exception
方式2:自定义一个运行时期的异常类:自定义类,并继承于 java.lang.RuntimeException
异常转译:
当位于最上层的子系统不需要关心底层的一场戏节时,常见的做法就是捕获原始的异常,把它转换为一个新的不同类型的异常,再抛出新的异常。
异常链:
把原始的异常包装为新的异常类,从而形成多个异常的有序排列,有助于查找生成异常类的根本原因。
Java7 的异常新特性(Android 用不到 Java7,支持 Java5/Java6 的语法)
1:增强的 throw
2:多异常捕获
3:自动资源关闭
Java7 中处理抛出异常更加精确了,不再笼统地使用 Exception 声明抛出
处理异常的原则:
1:异常只能用于非正常情况,try-catch 的存在也会影响性能
2:需要为异常提供说明文档,比如 java.doc,如果自定义了异常或某一个方法抛出了异常,应该记录在文档注释中
3:尽可能避免异常
4:异常的粒度很重要,应该为一个基本操作定义一个 try-catch 块,不要为了简便,将几百行代码放到一个 try-cathc 块中
5:不建议在循环中进行异常处理,应该在循环外对异常进行捕获处理(在循环之外使用 try-catch)
6:自定义异常尽量使用 RuntimeException 类型
捕获异常的语句块运行顺序:
public class ExceptionTest {
public static void main(String[] args) {
System.out.println(testMethod());
}
static int testMethod() {
int t = 1;
try {
System.out.println("进入try语句块----t:" + t);
t++;
System.out.println(t / 0);
System.out.println("离开try语句块----t:" + t);
return t;
} catch (ArithmeticException e) {
System.out.println("进入ArithmeticException异常----t:" + t);
t++;
System.out.println("结束ArithmeticException异常----t:" + t);
return t;
} catch (Exception e) {
System.out.println("进入Exception异常----t:" + t);
t++;
System.out.println("离开Exception异常----t:" + t);
return t;
} finally {
System.out.println("进入finally语句块----t:" + t);
t = 10;
System.out.println("离开finally语句块----t:" + t);
return t;
}
}
}
输出结果为:
进入try语句块----t:1
进入ArithmeticException异常----t:2
结束ArithmeticException异常----t:3
进入finally语句块----t:3
离开finally语句块----t:10
10