-------android培训、java培训、期待与您交流! ----------
Java是一门成熟的编程语言,提供了完善的异常处理机制。Java的异常处理主要依赖try、catch、finally、throw、throws这5个关键字。
其中try块后紧跟花括号构成try块,用来写可能引发异常的代码;catch后可跟异常类型和代码块构成catch块,主要用来处理该类型的异常;
finally块可放置在catch块后,用于释放在try块中打开的资源。
1. 异常处理机制
Java的异常处理将业务逻辑代码和错误处理代码分离,提供了更好的可读性。
Java试用try catch进行异常处理,语法结构如下所示:
try
{
//业务逻辑代码
}
catch (Exception e)
{
//异常处理代码
System.out.println(“程序出错");
}
抛出异常:当执行try块中的代码出现异常是,系统将创建一个该异常的对象,并提交到Java运行时环境,该过程被称为throw异常。
捕获异常:当Java运行时环境接受到异常对象后,会寻找能够处理该异常的catch块,如果找到合适的catch块,则将该异常交给该catch异常处理。
注意:不管执行的程序是否在try中,甚至是catch块中的代码,当出现异常后,系统都会创建该异常的对象。如果程序没有为该异常定义任何的catch块,则该异常无法被处理,Java程序将会退出。
2. 异常类的继承关系
catch块的寻找方式:当try块中出现异常后,系统将依次判断该异常对象是否属于catch后跟的异常类或其子类,如果是则将异常对象传递给该catch后的异常形参变量,并执行catch块的代码处理异常。
注意:try块的花括号不能省略;try块中定义的变量是局部变量,catch块中无法使用。
Java提供了丰富的异常类,这些异常类之间有严格的继承关系,如图所示。
Java将所有的非正常情况分为两种,异常(Exception)和错误(Error),他们都继承制Throwable父类。
- Error错误:一般是虚拟机出现问题,例如系统崩溃,虚拟机错误,动态链接失败等。Error错误不可恢复并且不能捕捉,一单出现系统将中断。不能用catch进行捕获。
- Exception异常:Runtime,SQL等。
下面是一些简单的异常捕捉例子:
public class DivTest {
public static void main(String[] args) {
try {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
int c = a / b;
System.out.println("您输入的两个数相除的结果是:" + c );
}
catch (IndexOutOfBoundsException ie) {
System.out.println("数组越界:运行程序时输入的参数个数不够");
}
catch (NumberFormatException ne) {
System.out.println("数字格式异常:程序只能接受整数参数");
}
catch (ArithmeticException ae) {
System.out.println("算术异常");
}
catch (Exception e) {
System.out.println("未知异常");
}
}
}
注意:在异常处理时要记住先处理小异常在处理大异常,将异常子类放在前面。
3. finally块的使用
finally总会被执行(除非在try块或catch块中执行了退出JVM方法(System.exit())),所以一般用来关闭打开的各种物理资源。
当程序执行到try或catch中的return或者throw语句时,并不会立即结束方法,而是会寻找是否存在finally块,如果有则先执行finally块中的代码,再执行return或throw语句。如果finally中包含了return语句,那么方法会被介绍,导致try或catch中的return等语句得不到执行,可到导致程序出错。
示例:
public class FinallyTest
{
public static void main(String[] args)
{
FileInputStream fis = null;
try
{
fis = new FileInputStream("a.txt");
}
catch (IOException ioe)
{
System.out.println(ioe.getMessage());
//return语句强制方法返回
return ; //①
//使用exit来退出虚拟机
//System.exit(1); //②
}
finally
{
//关闭磁盘文件,回收资源
if (fis != null)
{
try
{
fis.close();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
System.out.println("执行finally块里的资源回收!");
}
}
}
4. Checked异常和Runtime异常
Java的异常分为两大类:Checked异常和Runtime异常。
RuntimeException类及其的子类的实例Runtime异常,除此之外的实例为Checked异常。
Checked异常必须被显示的处理,处理方法如下:
①使用try..catch处理异常
②使用throws抛出该异常
5. 使用throws抛出异常:
使用throws抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理,如果main方法也不知道如何处理这种类型的异常,也可以用throws抛出,将异常交给JVM处理。JVM对异常的处理方式是,打印异常的跟踪栈信息,并中止程序的运行。
throws只能在方法签名后面使用,可以同时声明抛出多个异常类,多个异常类之间用逗号隔开,其语法格式如下:
throws ExceptionClass1, ExceptionClass2...
一旦使用了throws语句声明抛出异常,在方法中就无法通过try..catch块捕获该异常。
示例:
public class ThrowsTest {
public static void main(String[] args)
throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
}
}
上面的程序不处理异常,一旦发生异常,JVM会打印异常信息,并结束程序的运行。
如果某个方法加入了throws的声明,该方法希望他的调用者来处理该异常,如下面的程序所示:
public class ThrowsTest2 {
public static void main(String[] args)
throws Exception {
//因为test()方法声明抛出IOException异常,
//所以调用该方法的代码要么处于try...catch块中,
//要么处于另一个带throws声明抛出的方法中。
test();
}
public static void test()throws IOException {
//因为FileInputStream的构造器声明抛出IOException异常,
//所以调用FileInputStream的代码要么处于try...catch块中,
//要么处于另一个带throws声明抛出的方法中。
FileInputStream fis = new FileInputStream("a.txt");
}
}
6. 使用throw抛出异常
如果需要在程序中自行抛出异常,则应该使用throw语句,throw语句可以单独使用,throw语句抛出的不是异常类,而是一个异常示例,而且每次只能抛出一个异常示例。throw语句的语法格式如下:throw ExceptionInstance;
如果throw抛出的是checked异常,则该throw语句要么处于try块中,要么放在一个带throws声明抛出的方法中。如果抛出的是Runtime类型异常,那么该语句无需放在try块中,方法也不用抛出改异常,交由JVM自行处理。
示例:
public class ThrowTest {
public static void main(String[] args) {
try {
// 调用声明抛出Checked异常的方法,要么显式捕获该异常
// 要么在main方法中再次声明抛出
throwChecked(-3);
}
catch (Exception e) {
System.out.println(e.getMessage());
}
// 调用声明抛出Runtime异常的方法既可以显式捕获该异常,
// 也可不理会该异常
throwRuntime(3);
}
public static void throwChecked(int a)throws Exception {
if (a > 0) {
//自行抛出Exception异常
//该代码必须处于try块里,或处于带throws声明的方法中
throw new Exception("a的值大于0,不符合要求");
}
}
public static void throwRuntime(int a) {
if (a > 0) {
//自行抛出RuntimeException异常,既可以显式捕获该异常
//也可完全不理会该异常,把该异常交给该方法调用者处理
throw new RuntimeException("a的值大于0,不符合要求");
}
}
}
通过上述程序可看出,自行抛出Runtime异常比自行抛出Checked类型的灵活性更好。同样,抛出Checked异常让编译器提醒程序员必须处理该异常。