-------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异常让编译器提醒程序员必须处理该异常。