异常:当程序运行时,发生了不可预期的事件导致程序中断就是异常。异常发生时该怎么处理呢,c语言中,发生异常时返回某一数值作为执行状态。在java中提供了优秀的异常捕获机制。
先来看一下异常有哪些种类,java中异常的父类时Throwable,其子类是Error和Exception。Error类代表运行时环境发生的错误,程序中是不用捕获这类异常的。Exception类中的异常是可以捕获的,Exception类的子类包括了:RuntimeException运行时异常和Checked Exception受检异常,从盗了这张图,借用一下,里面有所有类的继承关系
程序中难免会出现异常,应该秉持两种规则:不忽视和不丢弃;一般来讲当程序出现异常时我们通常会采用一下几种方式来处理:
1.捕捉并处理异常,防止它传播给调用端;进而遏制异常的进一步传播。
2.捕捉,并再次原样抛出异常给调用端,将异常原样throw。
3.捕捉,然后抛出一个新异常给调用端,确保新抛出的异常包含原有异常信息,但可进一步封装,调用throw将新异常 抛出。
4.不捕捉,任由它传播给调用端,并且该函数会马上中断,不会继续执行该函数的后续语句。
对于第一种处理操作是不推荐的,因为捕捉完不做处理,是很危险的,例如如下代码,不着玩异常,就空着不做处理,程序有可能因为这种异常返回错误结果:
try {
result = Integer.parseInt(str);
} catch(NumberFormatException nfex) {
}
对于第二种方式是合适的(以下代码是第二种方式),其他第三第四种是可以的,只是上述第一种方式不建议。异常处理里面啥也没有,程序将继续执行。
try {
result = Integer.parseInt(str);
} catch(NumberFormatException nfex) {
throw new Exception("asdad");
}
我们要知道一个知识点,当你没有捕获异常时,异常将导致程序结束。当你捕获异常时程序将继续往下执行。
首先看一下如下代码将抛出的异常:
public class ExceptionDemo {
public static void main(String[] args) {
try {
System.out.println(string2Int("asdadads"));
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
/**
* 将字符串转成整数
* @param str
* @return
*/
public static int string2Int(String str) {
int result = 0;
result = Integer.parseInt(str);
return result;
}
}
打印结果:
For input string: "asdadads"
java.lang.NumberFormatException: For input string: "asdadads"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at ExceptionDemo.string2Int(ExceptionDemo.java:42)
at ExceptionDemo.main(ExceptionDemo.java:16)
可以看到,是报异常了,有异常信息,和异常的代码流。那如何处理异常让程序正常返回并不影响后续执行呢?请看如下代码:
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println(string2Int("asdadads"));
}
@SuppressWarnings("finally")//注解表示忽略finally语句块中的警告
public static int string2Int(String str) {
int result = 0;
try {
result = Integer.parseInt(str);
} catch(NumberFormatException nfex) {
//对异常进行处理,一般是两种用途:日志和对异常情况的处理
System.out.println(nfex.getMessage());
}
return result;
}
}
执行结果是:
For input string: "asdadads"
0
可以看到与上一程序的区别在于这个程序在函数内部就处理了异常,处理完异常后程序不中断,继续执行,也不用抛出异常,外层调用该函数的地方也不用作异常捕获处理。程序具有较强的健壮性。
好的我们继续来看一个异常中的问题,异常覆盖,啥叫异常覆盖呢,请看以下程序,您觉得结果是什么,思考一分钟,然后揭晓答案:
public class ExceptionDemo {
public static void main(String[] args) {
try {
System.out.println(testCoverException("asdadads"));//这输入是会报异常的
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
/**
* 将字符串转成整数
* @param str
* @return
* @throws Exception
*/
@SuppressWarnings("finally")
public static int testCoverException (String str) throws Exception {//申明需要抛出的异常
int result = 0;
try {
result = Integer.parseInt(str);
} finally {
throw new Exception("amazing");
}
}
}
答案是:打印amazing。
你会想为什么是amzing,而不抛出NumberFormatException异常信息呢。可以看到该程序是会抛出两个异常的,确实,程序执行抛出了两个异常,一个是NumberFormatException一个是Exception("amzing")但是异常是会被覆盖掉的,最终程序只抛出一个异常,后面的异常会覆盖前面的异常。回到程序,在出现NumberFormatException后因为没有catch语句做异常处理,这边默认异常处理为空,继续执行finally语句抛出新异常,覆盖老异常。对于这种异常覆盖的解决将在下一篇中说明。
// try和catch可以连用,try-catch- finally可以连用,这是众所周知的,但是try、catch、finally这三个关键字
// 却不能单独使用,如果在程序中只想try而不去catch也是可以的,但是try的后面必须跟有finally。
* 我们知道在java中,无论是return还是抛出异常,都会导致方法的结束。但是java中finally语句又必须执行,
* 所以finally语句的执行时机应该是在try语句中的return语句之前,或者catch语句中throw语句执行之前。
* 不然,无论是return语句执行,还是throw语句执行,都将导致finally语句无法得到执行。又由于在finally
* 语句中,书写了return语句,就是这么个return语句,将导致方法的提前结束,因而无论是try中的return语句,
* 还是catch中的throw语句,都将失去执行的机会,仿佛被覆盖掉了一般。