所谓异常,就是指在JAVA语言中,程序执行的过程中发生了不正常的情况。在我们通常情况下编写代码时编译时出现的那些语法错误和逻辑错误不是异常。
对于JAVA中的异常,可以分为error(错误)和exception(异常)两大类。
对于error,它指的是JAVA虚拟机无法解决的严重的问题,一般来说我们代码编写员是不编写相应的代码对他进行处理的。
JAVA中的异常处理主要处理的是exception这类异常,它是由于编程时存在一些逻辑错误或者时一些外在的因素所导致的问题(比如说:访问空指针,尝试去访问不存在的文件,网络未连接或者网络中断),它是可以让我们使用针对性的代码进行处理的。
那么如何去针对这些错误去做相应的处理呢,毕竟在程序运行时发生了异常,我们不能直接遇到错误就终止程序的运行,所以这就需要由我们在进行程序的编写时候,去考虑很多因素了,对于exception,判断异常是不是为exception,主要就是看提示错误类型后缀是否为'Exception',大致分为两种,分别时编译时异常和运行时异常(RuntimeException),在exception中,除了RuntimeException,其余的都是编译时异常。
常见的运行时异常(RuntimeException)如下:
1:数组下标异常(java.lang.ArrayIndexOutOfBoundsException)
它表示数组在输出时下标越界了。
2:算术异常(java.lang.ArithmeticException)
它表示你的除数为0。
3:类型转换异常(java.lang.ClassCastException)
4:空指针异常(java.lang.NullPointerException)
那么我们如何去处理异常呢(Exception)
首先,我们可以说一下JAVA中对异常处理的一个模型,叫做“抓抛模型”。
那么什么是抓抛模型呢,先说一下这个所谓的“抛”,它是指在我们程序运行的时候,如果出现了异常,就会在出现了异常的代码处生成一个对应的异常类型的对象,并将它抛出,一旦抛出了这个异常对象,程序就会终止执行,而被抛出的对象就会抛给方法的调用者(JVM)
“抓”,所谓的抓就是抓住跑出来的异常类的对象,也就是异常处理的方式,JAVA中有两种异常的处理方式
①即利用try....catch....finally的组合语句进行异常的处理,其语法如下
try{
//这里放入可能会出现异常的代码
}catch(Exception的类型1,a1){
//这里放入处理异常相应的方式
}catch(Exception的类型2,a2){
//这里放入处理异常相应的方式
}finally{
//这里放的是无论如何都会执行的代码,即不管出不出现异常,这里的代码必须执行(*如果方法中有return语句与finally同时存在时,先执行finally后再执行return*),但是finally可以写也可以不写,由本身的情况来确定
}
下面来举一个例子:
import
java.util.InputMismatchException;
import
java.util.Scanner;
public
class
test2 {
public
static
void
main(String[]
args
)
{
int
i
;
test2
a
=
new
test2();
System.
out
.println(
a
.test());
//打印返回的最后数
}
public
int
test(){
Scanner
a
=
new
Scanner(System.
in
);
try
{
int
i
=
a
.nextInt();
System.
out
.println(
"i"
);
return
1;
}
catch
(InputMismatchException
e1
){
System.
out
.println(
"输入的类型错误!"
);
}
finally
{
return
2;
}
}
}
//输入的类型错误!
//2
从输出结果可以明显的看到,即使方法在执行到一半时有了返回值,但是在这个方法中还存在finally,就会去执行finally中的语句。
需要我们注意的是try中声明的变量类似于局部变量,除了tyr语句后是不能够再次被调用的。而我们在catch中对异常进行处理时可以自己写方式(你可以显示的处理,也可以不显示的处理,但这仅仅只针对于运行异常,对于出现的编译异常还是要进行显示处理的),也可以调用其本身自带的一些函数进行处理,比如getmessage(),printStackTrace()等等;由于catch语句是自上而下进行匹配然后去执行的,那么当执行了一个catch语句后,不会再执行其余的catch语句,执行完后就会跳过其后的多条catch语句(并且try...catch语句是可以嵌套的,这里有点类似于if...else if....语句),然后继续执行后面的代码。
还有需要注意的一点就是对于两个异常来说,如果是包含关系,必须将子类放在父类的上面,不然就会报错的,这一点一定要注意。
JAVA中处理异常的第二个方式叫做显示的抛出异常(throws):
言外之意就是当在一个方法运行的过程中,如果出现了某种可能异常,而又不知道该如何去处理这个异常的时候,直接将它抛给该方法的调用者,使用显示抛出异常的语法如下
public
static
void
test()
throws
FileNotFoundException,IOException{}
该条语句就表示如果test方法出现了异常,就将它抛给它的调用者去解决这个异常(通常是利用try-catch-finally方法去解决的),如果调用者也不能解决,就需要一层一层的抛下去了,直到问题得到解决,当抛到main方法时,main也没能解决,那就会抛给JVM了。
下面就来看一个具体的处理异常的例子
package
test2;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.IOException;
public
class
test2 {
public
static
void
main(String[]
args
)
{
try
{
test();
}
catch
(FileNotFoundException
e
) {
System.
out
.println(
e
.getMessage());
}
catch
(IOException
e
) {
System.
out
.println(
e
.getMessage());
}
}
public
static
void
mod1()
throws
FileNotFoundException,IOException{
test();
}
public
static
void
test()
throws
FileNotFoundException,IOException{
FileInputStream
frs
=
new
FileInputStream(
new
File(
"hello1.txt"
));
int
b
;
while
((
b
=
frs
.read())!=1)
{
System.
out
.print((
char
)
b
);
}
frs
.close();
}
}//
该程序中,我在test2包下有一个文件名为Hello.txt的一个文档,但是在test()方法调用这个文档的时候发现找不到这个文档,而又不知道怎么去处理,于是就将它抛给了它的调用者mod1(),mod1()也不知道如何处理,就继续将它抛给主函数,让主函数进行try-catch的处理。
很显然,上面说的是自动的抛出异常,那么在JAVA中,同样可以手动抛出异常,手动抛出异常的关键字为throw(要注意这里和自动抛出异常不一样,它是不加s的关键字!),使用手动抛出异常就会让异常处理显得很灵活了,在一个方法中你可以使用多个手动抛出异常,其基本的使用方法如下:
就拿运行异常来举个例子 throw new RuntimeException("运行时异常");它可以写在方法体中,而不是像throws一样只能写在方法的小括号后面。
最后说一点,若是RuntimeExcepton,可以不显示的处理,而当异常为Exception时,必须显示的处理。