异常
1 什么是Java中的异常
Java中的异常就是Java程序在运行时会出现的一些错误,这些错误会影响程序正常的指令流程,从而导致程序不能够继续运行下去。打个比方,Java中出现的异常就是我们在现实世界中的生病,有的病可以预防,有的病可以治疗,有的病依照目前的医疗水平还不能治疗。Java异常也是如此,可以避免和处理,也有处理不了的。
在开发过程中,作为程序开发者,我们尽量的去避免这些可以避免的异常,尽量去处理这些可以处理的异常。
2 怎么描述Java异常
在开发者的世界里,有一句话特别经典:万物皆对象。所以说Java中出现的所有异常都会用对象来描述它,这些描述异常的类在Java中有一个超类,即Throwable类,该类定义了描述程序中出现的异常的基本模板。
Throwable类直接衍生出来的类只有两个:Error和Exception。Error类就是我们之前所说的无法处理的Java异常,一般是Java虚拟机出现的错误(如果没有了解过虚拟机的话,就不要深究该问题,笔者也没有了解过JVM);Exception才是我们在写程序时经常会遇见的Java异常,在编写程序时,99%遇见的都是该类异常。
Error是我们编写的程序自身无法处理的异常,Exception是我们程序自身可以处理的异常。
3 Exception的描述
关于Exception中的分类有不同的看法,不过一般的都认同上图中的分类:运行时和非运行时异常。这两种分类怎么理解呢?
就像他两的名字中的“运行”两字,我们都知道Java编写的源代码是需要编译的(将.java文件编译成.class)文件,然后才会运行字节码文件。所以运行时异常就是程序在运行的时候出现的异常,非运行时异常就是在编译阶段出现的异常(比如我们用Myeclipse编写阶段编写Java代码时需要处理的异常)。
4 怎么处理异常
处理异常有两个阶段,而且是有先后顺序的:抛出异常和捕获异常。
抛出异常就两个关键字:throw和throws,而且两个关键字必须是一起存在的,缺一不可。方法声明处用throws声明抛出的是什么类型的异常,用throw在方法中抛出具体的异常对象(new出来的异常对象)。
捕获异常就三个关键字:try、catch和finally,其中的组合有规则,只能有一个try和一个finally,catch块可以有0个或多个。
抛出异常:除数不能为零的异常
public void testThrow(int a, int b) throws ArithmeticException {
if(b == 0) throw new ArithmeticException();
}
捕获异常:try...catch...finally
public static void main(String[] args) {
try {
int count = 5/0;
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println(e.getMessage());
} catch(Exception e) {
System.out.println(e.getMessage());
} finally {
System.out.println("方法返回前必须执行的代码块");
}
}
5 异常应该注意的问题
异常理解起来并不是很难,关键的是异常的细节。一些细节的问题才是笔试和面试当中常见的问题。
try不能单独存在
try只能和catch或者finally或者catch和finally联合使用,它不能单独存在。
try语句块是是我们需要监测的代码,即可能会出现异常的代码块。
catch不能单独存在
catch只能够和try语句块联合使用,而且可以有多个catch语句块。
finally语句块一定会执行吗
在一般情况下,finally语句块是一定会执行的。但是我们要知道也有特殊情况:电脑没电、程序强制退出、线程死亡等等。
如果try和catch语句块没有return,finally语句块是一定会执行的。
如果try和catch语句块有return,那么一定会在return之前执行finally语句块(如果finally语句块里也有return,那么就会在finally语句块中返回)。
如果catch语句块中有抛出异常,那么与throw同一个代码块之后的代码不会执行(比如try代码块、catch代码块),但是finally还是会执行。
大家可以猜猜下面的输出结果:
package testException;
/**
*
* @author Administrator
* 测试异常的try、catch、finally的关系
*/
public class TestException1 {
public TestException1() {
}
@SuppressWarnings("finally")
boolean test1() throws Exception {
boolean flag = true;
try {
System.out.println("test2的try语句块");
flag = test2();
} catch (Exception e) {
System.out.println("test1的catch语句块");
flag = false;
throw e;
} finally {
System.out.println("test1的finally语句块,方法返回值=" + flag);
return flag;
}
}
@SuppressWarnings("finally")
boolean test2() throws Exception {
boolean flag = true;
try {
flag = test3();
if (!flag) {
return false;
}
System.out.println("test2的try语句块");
return flag;
} catch (Exception e) {
System.out.println("test2的catch语句块");
flag = false;
throw e;
} finally {
System.out.println("test2的finally语句块,方法返回值=" + flag);
return flag;
}
}
@SuppressWarnings("finally")
boolean test3() throws Exception {
boolean flag = true;
try {
for (int i = 4; i >= -1; i--) {
int c = 10 / i;
System.out.println("i=" + i);
}
System.out.println("test2的try语句块");
return true;
} catch (Exception e) {
System.out.println("test3的catch语句块");
flag = false;
throw e;
} finally {
System.out.println("test3的finally语句块,方法返回值=" + flag);
return flag;
}
}
public static void main(String[] args) {
TestException1 testException1 = new TestException1();
try {
testException1.test1();
} catch (Exception e) {
e.printStackTrace();
}
}
}
finally语句块之后的代码一定会执行
不一定会执行。
无论有没有异常出现,只要出现了throw,那么就不会执行。
如果没有异常且try和catch语句块中没有return,则一定会执行。
如果有异常,那就看有没有catch语句块:如果有catch语句块且出现的异常是匹配的,那么会执行,否则不会执行。
匹配,是指try出现的异常是catch中异常类或者是其子类,那么就是匹配。
try {
int count = 5/0;
// } catch (ArithmeticException e) {
// // TODO: handle exception
// System.out.println(e.getMessage());
} catch(Exception e) {
System.out.println(e.getMessage());
} finally {
System.out.println("方法返回前必须执行的代码块");
}
System.out.println("finally语句块之后的代码执行了");