异常处理

异常

  异常实际上是异常事件的简称,许多不同的错误可以引起异常。若这些错误出现在Java方法中,该方法会创建一个异常对象,对象中包含异常类型、错误出现时程序的状态等信息,交到运行系统,这就是抛出异常。

  运行系统负责找出处理错误的方法,它往回搜索方法调用栈,直到找出一个合适的异常处理器(异常处理器处理的异常类型为抛出的异常类型)。这个过程称为捕获异常。若运行系统找不到合适的异常处理器,系统就会终止运行。

优点

  用异常处理错误有3个优点:

  1.处理错误的代码与正常代码分开。这样做既不会影响正常代码的逻辑结构,而且还可以知道哪一步出现错误,并分清楚出错后要做的事情。

  2.沿调用栈向上传送错误。Java的方法可以避开它抛出的异常,由它上一层调用方法处理。只有关心错误的方法才检测错误,其他方法可以把错误往上传。

  3.按错误类型和错误区别分组。Java的异常都是对象,异常分组是类与子类的自然结果。

分类

  异常可分为运行时刻异常和非运行时刻异常。

  运行时刻异常:运行时出现在JVM的异常,无需捕获或抛出。

  非运行时刻异常:合法操作所调用方法必须知道的有用信息,需要捕获或抛出。

自定义异常

  自定义的异常类需要继承java.lang.Exception类。通常情况下自定义的异常类除了提供无参构造方法,还提供一个传入错误信息参数的带参构造方法。Exception类本身也有同样的构造方法,所以直接通过super调用Exception类的构造方法即可。

 1 class MyException extends Exception {
 2 
 3     private static final long serialVersionUID = 1L;
 4 
 5     public MyException() {
 6         super();
 7     }
 8 
 9     public MyException(String msg) {
10         super(msg);
11     }
12 
13 }
MyException

处理异常

  可以在方法内创建异常处理器。异常处理器由3部分组成:

  try块:用于管理可能出现异常的语句。try块之后必须有catch块或finally块。

  catch块:用于声明异常处理器。catch块必须跟在try块或catch块之后。

  finally块:用于后续处理。finally块必须跟在try块或catch块之后。

  如果try块中出现的异常能够被catch块捕捉到,则能够执行异常处理器之后的代码。

 1 @Test
 2 void testExceptionHandling() {
 3     try {
 4         System.out.println("try");
 5         int i = 1 / 0;
 6     } catch (Exception e) {
 7         System.out.println("catch");
 8     } finally {
 9         System.out.println("finally");
10     }
11     System.out.println("next");
12 }
testExceptionHandling

  输出结果:

  

  如果try块中出现的异常不能被catch块捕捉到,则无法执行异常处理器之后的代码。

 1 @Test
 2 void testExceptionHandling() {
 3     try {
 4         System.out.println("try");
 5         int i = 1 / 0;
 6     } catch (NullPointerException e) {
 7         System.out.println("catch");
 8     } finally {
 9         System.out.println("finally");
10     }
11     System.out.println("next");
12 }
testExceptionHandling

  输出结果:

  

  当出现多个异常时,有两种解决方法:

  1.定义多个catch块。这样每种类型的异常都会有独立的处理方法。

 1 @Test
 2 void testExceptionHandling() {
 3     try {
 4         
 5     } catch (NullPointerException e) {
 6         
 7     } catch (ArithmeticException e) {
 8         
 9     }
10 }
testExceptionHandling

  2.在一个catch块中定义异常类型时使用“|”隔开多种异常类型。这样每种类型的异常处理的方法都一致。

1 @Test
2 void testExceptionHandling() {
3     try {
4         
5     } catch (NullPointerException | ArithmeticException e) {
6         
7     }
8 }
testExceptionHandling

  需要注意的是,try块、catch块、finally块相当于是定义局部代码块。也就是说,在一个块中定义的变量无法在其他块中使用。所以如果需要在try块中创建资源,则需要在try块之前声明,在try块中初始化资源,这样才能在finally块中释放资源。

 1 @Test
 2 void testCreateResources() {
 3     PrintStream ps = null;
 4     try {
 5         ps = new PrintStream(new FileOutputStream("test.txt"));
 6         int i = 1 / 0;
 7     } catch (Exception e) {
 8         
 9     } finally {
10         if (ps != null) {
11             ps.close();
12         }
13     }
14 }
testCreateResources

  上述释放资源显得比较麻烦,所以JDK 1.7之后的版本提供了一种新形式的try块语句。可以在try之后的“( )”中声明并初始化资源,如果有多个资源则使用“;”隔开。当try块结束时,资源会自动释放,无需调用close()方法。

1 @Test
2 void testCreateResources() {
3     try (PrintStream ps = new PrintStream(new FileOutputStream("test.txt"))) {
4         int i = 1 / 0;
5     } catch (Exception e) {
6         
7     }
8 }
testCreateResources

抛出异常

  抛出异常的方式有两种:

throws子句

  在方法声明处使用throws子句抛出方法体中可能出现的异常。调用该方法的方法需要对异常进行处理或抛出。

1 @Test
2 void testExceptionThrowing() throws FileNotFoundException {
3     new FileOutputStream("test.txt");
4 }
testExceptionThrowing

throw语句

  throw语句用于主动抛出定义的异常。使用了throw语句抛出的异常的方法需要处理或抛出该异常。

1 @Test
2 void testExceptionThrowing() {
3     try {
4         throw new MyException();
5     } catch (Exception e) {
6         
7     }
8 }
testExceptionThrowing
1 @Test
2 void testExceptionThrowing() throws Exception {
3     throw new MyException();
4 }
testExceptionThrowing
原文地址:https://www.cnblogs.com/lqkStudy/p/11044620.html