Groovy - 异常处理

  • 简述

    任何编程语言都需要异常处理来处理运行时错误,以便维持应用程序的正常流程。
    异常通常会破坏应用程序的正常流程,这就是我们需要在应用程序中使用异常处理的原因。
    例外大致分为以下几类 -
    • Checked Exception - 除了 RuntimeException 和 Error 之外,扩展 Throwable 类的类被称为检查异常,例如 IOException、SQLException 等。检查异常在编译时检查。
    一个经典案例是 FileNotFoundException。假设您的应用程序中有以下代码,它从 E 盘中的文件中读取。
    
    class Example {
       static void main(String[] args) {
          File file = new File("E://file.txt");
          FileReader fr = new FileReader(file);
       } 
    }
    
    如果文件 (file.txt) 不在 E 驱动器中,则会引发以下异常。
    捕获到:java.io.FileNotFoundException: E:\file.txt(系统找不到指定的文件)。
    java.io.FileNotFoundException: E:\file.txt(系统找不到指定的文件)。
    • 未经检查的异常- 扩展 RuntimeException 的类称为未经检查的异常,例如 ArithmeticException、NullPointerException、ArrayIndexOutOfBoundsException 等。未经检查的异常在编译时不检查,而是在运行时检查。
    一个经典案例是 ArrayIndexOutOfBoundsException,当您尝试访问大于数组长度的数组索引时会发生这种情况。以下是此类错误的典型示例。
    
    class Example {
       static void main(String[] args) {
          def arr = new int[3];
          arr[5] = 5;
       } 
    }
    
    执行上述代码时,将引发以下异常。
    捕获:java.lang.ArrayIndexOutOfBoundsException:5
    java.lang.ArrayIndexOutOfBoundsException:5
    • 错误- 错误是不可恢复的,例如 OutOfMemoryError、VirtualMachineError、AssertionError 等。
    这些是程序永远无法恢复的错误,将导致程序崩溃。
    下图显示了 Groovy 中异常的层次结构是如何组织的。这一切都基于 Java 中定义的层次结构。
    异常的层次结构
  • 捕获异常

    方法使用trycatch关键字的组合来捕获异常。try/catch 块放置在可能产生异常的代码周围。
    
    try { 
       //Protected code 
    } catch(ExceptionName e1) {
       //Catch block 
    }
    
    所有可能引发异常的代码都放在受保护的代码块中。
    在 catch 块中,您可以编写自定义代码来处理您的异常,以便应用程序可以从异常中恢复。
    让我们看一下我们在上面看到的类似代码的示例,用于访问索引值大于数组大小的数组。但这次让我们将代码包装在 try/catch 块中。
    
    class Example {
       static void main(String[] args) {
          try {
             def arr = new int[3];
             arr[5] = 5;
          } catch(Exception ex) {
             println("Catching the exception");
          }
          
          println("Let's move on after the exception");
       }
    }
    
    当我们运行上面的程序时,我们将得到以下结果 -
    
    Catching the exception 
    Let's move on after the exception
    
    从上面的代码中,我们将 try 块中的错误代码包装掉了。在 catch 块中,我们只是捕获异常并输出发生异常的消息。
  • 多个 catch 块

    一个人可以有多个 catch 块来处理多种类型的异常。对于每个 catch 块,根据引发的异常类型,您将编写相应的代码来处理它。
    让我们修改上面的代码以专门捕获 ArrayIndexOutOfBoundsException。以下是代码片段。
    
    class Example {
       static void main(String[] args) {
          try {
             def arr = new int[3];
             arr[5] = 5;
          }catch(ArrayIndexOutOfBoundsException ex) {
             println("Catching the Array out of Bounds exception");
          }catch(Exception ex) {
             println("Catching the exception");
          }
          
          println("Let's move on after the exception");
       } 
    }
    
    当我们运行上面的程序时,我们将得到以下结果 -
    
    Catching the Aray out of Bounds exception 
    Let's move on after the exception
    
    从上面的代码可以看出,ArrayIndexOutOfBoundsException catch 块首先被捕获,因为它意味着异常的条件。
  • Finally 块

    finally块跟在try 块或 catch 块之后。finally 代码块始终执行,无论是否发生异常。
    使用 finally 块允许您运行任何您想要执行的清理类型语句,无论受保护代码中发生什么。该块的语法如下所示。
    
    try { 
       //Protected code 
    } catch(ExceptionType1 e1) { 
       //Catch block 
    } catch(ExceptionType2 e2) { 
       //Catch block 
    } catch(ExceptionType3 e3) { 
       //Catch block 
    } finally {
       //The finally block always executes. 
    }
    
    让我们修改上面的代码并添加 finally 代码块。以下是代码片段。
    
    class Example {
       static void main(String[] args) {
          try {
             def arr = new int[3];
             arr[5] = 5;
          } catch(ArrayIndexOutOfBoundsException ex) {
             println("Catching the Array out of Bounds exception");
          }catch(Exception ex) {
             println("Catching the exception");
          } finally {
             println("The final block");
          }
          
          println("Let's move on after the exception");
       } 
    } 
    
    当我们运行上面的程序时,我们将得到以下结果 -
    
    Catching the Array out of Bounds exception 
    The final block 
    Let's move on after the exception
    
    以下是 Groovy 中可用的异常方法 -

    public String getMessage()

    返回有关已发生异常的详细消息。此消息在 Throwable 构造函数中初始化。

    public Throwable getCause()

    返回由 Throwable 对象表示的异常原因。

    public String toString()

    返回与 getMessage() 结果连接的类的名称

    public void printStackTrace()

    将 toString() 的结果与堆栈跟踪一起打印到 System.err,即错误输出流。

    public StackTraceElement [] getStackTrace()

    返回一个数组,其中包含堆栈跟踪中的每个元素。索引 0 处的元素表示调用堆栈的顶部,数组中的最后一个元素表示调用堆栈底部的方法。

    public Throwable fillInStackTrace()

    使用当前堆栈跟踪填充此 Throwable 对象的堆栈跟踪,添加到堆栈跟踪中的任何先前信息。

    例子

    以下是使用上面给出的一些方法的代码示例 -
    
    class Example {
       static void main(String[] args) {
          try {
             def arr = new int[3];
             arr[5] = 5;
          }catch(ArrayIndexOutOfBoundsException ex) {
             println(ex.toString());
             println(ex.getMessage());
             println(ex.getStackTrace());  
          } catch(Exception ex) {
             println("Catching the exception");
          }finally {
             println("The final block");
          }
          
          println("Let's move on after the exception");
       } 
    }
    
    当我们运行上面的程序时,我们将得到以下结果 -
    
    java.lang.ArrayIndexOutOfBoundsException: 5 
    5 
    [org.codehaus.groovy.runtime.dgmimpl.arrays.IntegerArrayPutAtMetaMethod$MyPojoMetaMet 
    hodSite.call(IntegerArrayPutAtMetaMethod.java:75), 
    org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) ,
    org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) ,
    org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133) ,
    Example.main(Sample:8), sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ,
    java.lang.reflect.Method.invoke(Method.java:606),
    org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93),
    groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325),
    groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1443),
    org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:893),
    groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:287),
    groovy.lang.GroovyShell.run(GroovyShell.java:524),
    groovy.lang.GroovyShell.run(GroovyShell.java:513),
    groovy.ui.GroovyMain.processOnce(GroovyMain.java:652),
    groovy.ui.GroovyMain.run(GroovyMain.java:384),
    groovy.ui.GroovyMain.process(GroovyMain.java:370),
    groovy.ui.GroovyMain.processArgs(GroovyMain.java:129),
    groovy.ui.GroovyMain.main(GroovyMain.java:109),
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ,
    java.lang.reflect.Method.invoke(Method.java:606),
    org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:109),
    org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:131),
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method),
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57),
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ,
    java.lang.reflect.Method.invoke(Method.java:606),
    com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)]
     
    The final block 
    Let's move on after the exception