异常实际上是异常事件的简称,许多不同的错误可以引起异常。若这些错误出现在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 } testExceptionHandling2.在一个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子句抛出方法体中可能出现的异常。调用该方法的方法需要对异常进行处理或抛出。
1 @Test 2 void testExceptionThrowing() throws FileNotFoundException { 3 new FileOutputStream("test.txt"); 4 } testExceptionThrowingthrow语句用于主动抛出定义的异常。使用了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