本文主要围绕异常的三大类问题展开:什么是异常;异常产生的原因;异常的分类
一:异常概念:
Java中的异常(Exception)又称例外,是一个在程序执行期间发生的事件,它中断正在执行的程序的正常指令流。为了能够及时有效地处理程序中的运行错误,必须使用异常类。
二:异常的分类
Throwable 是 Java 语言中所有错误或异常的超类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。
实例分为 Error 和 Exception 两种。
1)Error类代表了编译和系统的错误,不允许捕获;
2)Exception类代表了标准Java库方法所激发的异常。Exception类还包含运行异常类Runtime_Exception和非运行异常类Non_RuntimeException(CheckedException)这两个直接的子类。
运行时异常:RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。 如果出现RuntimeException,那么一定是程序员代码书写导致的错误。
eg:NullPointerException 、 ClassCastException ;
非运行时异常:即可检查异常,一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强
制程序去捕获此类异常,即会出现要求你把这段可能出现异常的程序进行 try catch,该类异常一
般包括几个方面:
- 试图在文件尾部读取数据
- 试图打开一个错误格式的 URL
- 试图根据给定的字符串查找 class 对象,而这个字符串表示的类并不存在
eg:I/O 错误导致的 IOException、SQLException
3)Throw 和 throws 的区别
throws 用在函数上,后面跟的是异常类,可以跟多个。作用:用来声明异常
throw 用在函数内,后面跟的是异常对象。作用:抛出具体的问题对象
注:
throws 表示出现异常的一种可能性,并不一定会发生这些异常;
throw 则是抛出了异常,执行 throw 则一定抛出了某种异常对象。
首先明确:finally语句在try或catch中的return语句执行之后返回之前执行finally中的语句,但是finally中的修改语句不会影响try或catch中 return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回
三:异常的处理
首先明确:finally语句在try或catch中的return语句执行之后返回之前执行finally中的语句,但是finally中的修改语句不会影响try或catch中 return已经确定的返回值,若finally里也有return语句则覆盖try或catch中的return语句直接返回
try、catch、finally 这个过程也就是这样,如果try catch finally 都有return: * 1、在没有异常的情况下,try 中的返回值先保存到临时区域里在去执行finally ,这个finally 有返回值,这个返回值将之前try中的保存到临时区域的值用返回的这个值替换,再将这个临时区域中的值返回给上一级方法。 * 2、如果有异常,则执行catch中的代码,这里的return 将返回一个返回值放到临时区域,再去执行finally ,这个finally有返回值,这样就将catch中存在临时区域中的值用这个finally 返回的值替换掉,在将这个临时区域的值返回给上一级方法。 * 3、如果finally中没有返回值,则它对返回值变量的操作不会影响临时区域的值,即catch的return语句返回的值不受影响。 * 如果finally语句有返回值,则此返回值将会替换掉临时区域原有的值。
具体如下分析:
1、异常处理过程
把会出现异常的程序段放在try中,当抛出异常的时候就会在系统中生成一个异常对象,然后进行查找捕获这个异常,然后进行处理这个异常,处理之后接着执行下面的程序。
出现异常之后如果没有进行捕获处理系统就会直接将这个异常栈的跟踪信息直接打印出来之后就结束这个程序的执行。
对于异常的处理方式有两种分别为:try{}catch{}finally{}和throws下面简单说一下这两者的区别和联系
请先看下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public
class
Test{
public
static
void
main(String[] args){
Test2 test2 =
new
Test2();
try
{
System.out.println(
"invoke the method begin!"
);
test2.method();
System.out.println(
"invoke the method end!"
);
}
catch
(Exception e){
System.out.println(
"catch Exception!"
);
}
}
}
class
Test2{
public
void
method()
throws
Exception{
System.out.println(
"method begin!"
);
int
a =
10
;
int
b =
0
;
int
c = a/b;
System.out.println(
"method end!"
);
}
}
很明显,答案出来了:
invoke the method begin!
method begin!
catch
Exception!
|
对于try{}catch{}finally{}而言,用户可能确定知道代码会出现相关的异常,把有可能出现问题的地方放到try中去执行,如果一旦出现异常,立刻终止当前代码的继续
执行,转而去执行catch{}里面的内容。对于这类异常用户已经处理了,不会在向上抛出。
对于throws而言,一般使用在方法名的后面,使用throws关键字的时候,一般是开发者不确定出现什么异常或者出现异常的情况可能有多种。这时开发者在方法后面加 throws关键字抛出相关的异常。对于调用该方法的其它开发者者必须捕获这个异常或者继续throws这个异常,把这个异常传递下去,交给其对应的父类去处理。
2、异常处理的执行顺序(针对try{}catch{}finally{}而言)
对于try{}catch{}finally{}而言,,它们的执行顺序很简单,如果在try{}中捕获相应的异常,中断当前代码的执行,转而去执行catch{}中的内容,最后去执行
finally{}中方法,一般来说finally中的方法都是会被执行的,其中finally中很大程度上用于资源的释放。
下面讲解一些我们java程序员需要注意的地方。
a、finally中的代码总是会执行吗?
答:no,如果一个方法内在执行try{}语句之前就已经return了,那么finally语句指定不会执行了。因为它根本没有进入try语句中; 如果在一个try语句中调用System.exit(0);方法,那么就会退出当前java虚拟机,那么finally也就没有执行的机会了。
b、finally在return之前执行还是在return之后执行?
答:很多人可能会说在return执行之前执行。我的答案是在return中间执行,是不是很特别,请按下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package
com.yonyou.test;
class
Test{
public
static
void
main(String[] args) {
System.out.println(method());
}
public
static
int
method(){
int
x=
1
;
try
{
return
x;
}
catch
(Exception e)
{
return
0
;
}
finally
{
++x;
}
}
}
|
请问输出的结果是多少呢?
正确答案是:1
下面我来讲解一下这个程序的执行过程,
首先程序在执行到try{}语句中的return方法后,就会先返回相应的值,并把相应的值存储在一个临时栈中去保存这个结果。这时临时栈中存储的值为1。
但是程序不会立刻返回,转而回去执行finally中的方法,++x,在finally执行完后,方法全部执行完,这时会再次调用return方法,注意这时
不在是返回值,而是告诉主调程序,被调程序已经执行完了,你可以接着去执行你主程序的其它方法了。但是请注意,此时返回的值还是原来保存在临时
栈中的值1。
为了更好的理解这个问题,我们看下面的程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package
com.yonyou.test;
class
Test{
public
static
void
main(String[] args) {
System.out.println(method());
}
public
static
int
method(){
try
{
return
1
;
}
catch
(Exception e)
{
return
0
;
}
finally
{
return
2
;
}
}
}
|
这时的正确答案又是多少呢?
没错是2,这里仅仅需要注意的是在try{}语句中执行到return 1 会在临时栈中存储值为1的变量。接着回去执行finally里面的内容,这时执行finally中的return 2;方法,这时
临时栈中的值就是变为 2,会覆盖原来临时栈中的值1.所以它的返回值为2。
c、finally方法是必须的吗?
不是,开发者可以根据自身的情况去决定是否使用finally关键字。