📜  Java中的异常

📅  最后修改于: 2020-04-04 07:10:40             🧑  作者: Mango

什么是异常

异常是不需要的或意外的事件,它在程序执行期间(即在运行时)发生,它破坏了程序指令的正常流程。

错误与异常

错误: 错误表示严重的问题,即合理的应用程序不应尝试捕获。
异常: 异常表示合理的应用程序可能尝试捕获的条件。
异常层次
所有异常和错误类型都是Throwable类的子类,Throwable类是层次结构的基类。一个分支以Exception为头。此类用于用户程序应捕获的异常条件。NullPointerException是此类异常的示例。Java运行时系统(JVM)使用另一个分支Error来指示与运行时环境本身(JRE)有关的错误。StackOverflowError是此类错误的示例。

JVM如何处理异常?
默认异常处理:无论何时在方法内部,如果发生异常,该方法都会创建一个称为“异常对象”的对象,并将其交给运行时系统(JVM)。异常对象包含异常的名称和描述,以及发生异常的程序的当前状态。创建异常对象并将其处理到运行时系统称为抛出异常。可能存在被调用以获取发生异常的方法的列表。该方法的有序列表称为“ 调用堆栈”。现在将发生以下过​​程。

  • 运行时系统搜索调用堆栈以查找包含可处理发生的异常的代码块的方法。该代码块称为异常处理程序
  • 运行时系统从发生异常的方法开始搜索,,。
  • 如果找到合适的处理程序,则将发生的异常传递给它。适当的处理程序意味着抛出的异常对象的类型与其可以处理的异常对象的类型匹配。
  • 如果运行时系统在调用堆栈上搜索了所有方法并且找不到合适的处理程序,则运行时系统会将Exception Object移交给默认的异常处理程序,它是运行时系统的一部分。该处理程序以以下格式打印异常信息,并异常终止程序。
    Exception in thread "xxx" Name of Exception : Description
    ... ...... ..  // Call Stack

    请参见下图以了解调用堆栈的流程。

    范例

    // Java程序展示异常如何被抛出
    class ThrowsExecp{
        public static void main(String args[]){
            String str = null;
            System.out.println(str.length());
        }
    }

    输出:

    Exception in thread "main" java.lang.NullPointerException
        at ThrowsExecp.main(File.Java:8)
    

    让我们看一个示例,该示例说明运行时系统如何在调用堆栈上搜索适当的异常处理代码:

    // Java程序说明运行时系统如何在调用堆栈上搜索适当的异常处理代码
    class ExceptionThrown
    {
        // 抛出异常(ArithmeticException). 
        // 合适的异常处理没有在此方法内找到
        static int divideByZero(int a, int b){
            // 如下会导致异常:ArithmeticException,除以零
            int i = a/b;
            return i;
        }
        // 运行时系统,寻找合适的异常处理,但是没有找到然后以与调用方法相反的顺序遍历调用堆栈
        static int computeDivision(int a, int b) {
            int res =0;
            try
            {
              res = divideByZero(a,b);
            }
            // 不匹配:ArithmeticException
            catch(NumberFormatException ex)
            {
               System.out.println("NumberFormatException发生");
            }
            return res;
        }
        // 这个方法内找到合适的异常处理
        public static void main(String args[]){
            int a = 1;
            int b = 0;
            try
            {
                int i = computeDivision(a,b);
            }
            // 匹配 ArithmeticException
            catch(ArithmeticException ex)
            {
                // getMessage会打印异常(这里是 / by zero)
                System.out.println(ex.getMessage());
            }
        }
    }

    输出:

    / by zero.

     

程序员如何处理异常

定制的异常处理: Java异常处理通过五个关键字进行管理:trycatchthrowthrowsfinally。简而言之,这是它们的工作方式。您认为会引发异常的程序语句包含在try块中。如果try块中发生异常,则将引发该异常。您的代码可以捕获此异常(使用catch块)并以某种合理的方式处理它。系统生成的异常由Java运行时系统自动引发。要手动引发异常,请使用关键字throw。从方法抛出的任何异常都必须通过throws进行指定。条款。在try块完成之后绝对必须执行的所有代码都放在finally块中。

try-catch子句(自定义异常处理)

考虑下面的Java程序。

// Java程序,展示try-catch子句
class GFG {
    public static void main (String[] args) {
        // 尺寸=4的array.
        int[] arr = new int[4];
        // 这个声明抛出异常
        int i = arr[4];
        // 下面语句不会被执行
        System.out.println("嗨,我要执行");
    }
}

输出:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
    at GFG.main(GFG.Java:9)

说明:在上面的示例中,数组的大小是定义的,即您只能访问索引0到3的元素。但是您尝试访问索引4的元素(错误),这就是它引发异常的原因。在这种情况下, JVM 异常终止程序。语句System.out.println(“嗨,我要执行”); 将永远不会执行。要执行它,我们必须使用try-catch处理异常。因此,为了继续程序的正常进行,我们需要try-catch子句。
如何使用try-catch子句

try {
// 你认为会抛出异常的代码
}
catch (ExceptionType1 exOb) {
// 对ExceptionType1的异常处理
}
catch (ExceptionType2 exOb) {
// 对ExceptionType2的异常处理
}
// 以下可选
finally {
// 在try代码块之后执行的code
}

要记住的要点:

  • 在一种方法中,可能存在多个可能引发异常的语句,因此将所有这些语句放在其自己的try块中,并为每个语句在自己的catch块中提供单独的异常处理程序。
  • 如果try块中发生异常,则该异常由与其关联的异常处理程序处理。要关联异常处理程序,我们必须在其后放置catch块。可以有多个异常处理程序。每个catch块都是一个异常处理程序,用于处理其参数指示的类型的异常。参数ExceptionType声明它可以处理的异常类型,并且必须是从Throwable类继承的类的名称。
  • 对于每个try块,可以有零个或多个catch块,但只有一个 finally块。
  • finally块是可选的。无论是否在try块中发生异常,它总是被执行。如果发生异常,它将在try和catch块之后执行 如果未发生异常,则将在try块之后执行。Java中的finally块用于放置重要代码,例如清理代码,例如关闭文件或关闭连接。

摘要