几乎所有的代码里面都会出现异常,为了保证程序在出现异常之后可以正常执行完毕,就需要进行异常处理。
看一下异常的继承类结构
所有的异常都是由Throwable继承而来
Error类描述了java运行时内部错误和资源耗尽错误。应用程序不抛出此类异常,这种内部错误一旦出现,除了告知用户并使程序安全终止之外,再无能为力。这种情况很少出现。
由于程序错误导致的异常属于RuntimeException;而如果程序本身没有问题,由于像I/O错误这类问题导致的异常属于IOException。
Java语言规范将派生于Error类或RuntimeException类的所有异常称为非受查异常;所有其他的异常称为受查异常。
1. 异常的影响
异常是导致程序中断执行的一种指令流。程序之中如果出现异常并且没有合理处理的话就会导致程序中止执行。
例子:正确程序
public class Test {
public static void main(String[] args) {
System.out.println("计算开始");
System.out.println("计算进行中 10/2 ="+10/2);
System.out.println("计算结束");
}
}
此时没有任何异常产生,程序可以正常执行完毕。
例子:产生异常
public class Test{
public static void main(String[] args) {
System.out.println("计算开始");
System.out.println("计算进行中 10/0="+10/0);
System.out.println("计算结束");
}
}
现在程序之中产生了异常,但是在异常语句产生之前的语句可以正常执行完毕,而异常产生之后程序直接进行了结束。为了保证程序出现异常后还可以继续向下执行,就需要异常处理。
2. 异常处理格式
异常处理的语法格式如下:
try{
有可能出现异常的语句;
} [catch (异常类 对象) {
} …]
[ finally {
异常的出口
}]
对于以上三个关键字,可以出现的组合:try … catch、
try … finally、try … catch … finally
例子:对异常进行处理
public class Test{
public static void main(String[] args) {
System.out.println("计算开始");
try {
System.out.println("计算进行中 10/0=" + 10 / 0);
}catch (ArithmeticException e){
System.out.println("处理异常结束");
}
System.out.println("计算结束");
}
}
以上代码虽然进行了异常处理,但是存在一个问题:你根本不知道程序产生了什么样的异常。所以为了明确的取得异常信息,可以直接输出异常类对象,或者调用所有异常类中提供的printStackTrace()方法进行完整异常信息的输出。
例子:取得异常完整信息
public class Test{
public static void main(String[] args) {
System.out.println("计算开始");
try {
System.out.println("计算进行中 10/0=" + 10 / 0);
}catch (ArithmeticException e){
e.printStackTrace();
}
System.out.println("计算结束");
}
}
例子:使用try … catch … finally进行处理
public class Test{
public static void main(String[] args) {
System.out.println("计算开始");
try {
System.out.println("计算进行中 10/0=" + 10 / 0);
}catch (ArithmeticException e){
e.printStackTrace();
}finally {
System.out.println("无论是否产生异常都会执行");
}
System.out.println("计算结束");
}
}
不管此时是否产生异常,最终都会执行finally程序代码,所以finally会作为程序统一出口。
例子:初始化参数进行运算
public class Test{
public static void main(String[] args) {
System.out.println("计算开始");
try {
Integer x = Integer.parseInt(args[0]);
Integer y = Integer.parseInt(args[1]);
System.out.println("计算进行中 10/0=" + x / y);
}catch (ArithmeticException e){
e.printStackTrace();
}catch(NumberFormatException e){
e.printStackTrace();
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
finally {
System.out.println("无论是否产生异常都会执行");
}
System.out.println("计算结束");
}
}
上述代码完全可以使用if…else判断,不使用异常处理也一样。如果想要更好的处理异常,必须清楚异常的处理流程。
3. throws关键字
在进行方法定义的时候,如果要告诉调用者本方法可能产生哪些异常,就可以使用throws方法进行声明。即,如果该方法出现问题后不希望进行处理,就使用throws抛出。
例子:使用throws定义方法
public class Test{
public static void main(String[] args) {
try{
System.out.println(div(10,0));
}catch (Exception e){
e.printStackTrace();
}
}
public static int div(int x, int y) throws Exception{
return x/y;
}
}
如果现在调用了throws声明的方法,那么在调用时必须明确的使用try…catch…进行捕获,因为该方法有可能产生异常,所以必须按照异常的方式来进行处理。
主方法本身也属于一个方法,所以主方法上也可以使用throws进行异常抛出,这个时候如果产生了异常就会交给JVM处理。
例子:主方法抛出异常
public class Test{
public static void main(String[] args) throws Exception{
int result = div(10,0);
}
public static int div(int x,int y) throws Exception{
return x/y;
}
}
- throw关键字
throw是直接编写在语句之中,表示人为进行异常的抛出。如果现在异常类对象实例化不希望由JVM产生而由用户产生,就可以使用throw完成。
例子:使用throw产生异常类对象
public class Test{
public static void main(String[] args) {
try{
throw new Exception("抛个异常玩玩");
}catch(Exception e){
e.printStackTrace();
}
}
}
- RuntimeException类
直接看一段代码
public class Test{
public static void main(String[] args) {
String str = "100";
int num = Integer.parseInt(str);
System.out.println(num*2);
}
}
parselnt的源码定义如下:
public static int parseInt(String S) throws NumberFormatException
这个方法上已经明确抛出异常,但是在进行调用的时候发现,即使没有进行异常处理也可以正常执行。这个就属于RuntimeException的范畴。
很多的代码都可能出现异常,如果所有可能产生异常的地方都进行强制性异常处理,这个代码就太复杂了。所以在异常设计的时候,考虑到一些异常可能是简单问题,所以将这类异常称为RuntimeException,也就是使用RuntimeException定义的异常类可以不需要强制性进行异常处理。