Error 和 Exception 区别是什么

3 篇文章 0 订阅

Error和Exception都是继承了Throwable 类。
Error是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比OutOfMemoryError 之类,都是 Error 的子类。
Exception 又分为可查(checked)异常不可查(unchecked)异常
可查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。
不可查异常就是所谓的运行时异常,类似 NullPointerException、ArrayIndexOutOfBoundsException 之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

 

异常的处理

在 Java 应用程序中,异常处理机制为:抛出异常捕捉异常

抛出异常:当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。

捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。

处理过程:产生异常状态时,如果当前的context不具备处理当前异常的能力,将在heap 上new
出来一个异常对象,停止当前执行路线,把产生的对象抛给更高层的context。
从方法中抛出的任何异常都必须使用throws子句。

捕捉异常通过try-catch语句或者try-catch-finally语句实现。

总体来说,Java规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error

Error 也是可以catch的
如果catch的异常在前面已经 有catch了 后面再catch 编译不通过。编辑器会提示你

异常处理的两个基本原则

  • 1、尽量不要捕获类似 Exception 这样的通用异常,而是应该捕获特定异常
    这是因为在日常的开发和合作中,我们读代码的机会往往超过写代码,软件工程是门协作的艺术,
    所以我们有义务让自己的代码能够直观地体现出尽量多的信息,而泛泛的 Exception 之类,
    恰恰隐藏了我们的目的。另外,我们也要保证程序不会捕获到我们不希望捕获的异常。
    比如,你可能更希望 RuntimeException 被扩散出来,而不是被捕获。进一步讲,除非深思熟虑了,
    否则不要捕获 Throwable 或者 Error,这样很难保证我们能够正确程序处理 OutOfMemoryError。

  • 2、不要生吞(swallow)异常
    这是异常处理中要特别注意的事情,因为很可能会导致非常难以诊断的诡异情况。
    如果我们不把异常抛出来,或者也没有输出到日志(Logger)之类,程序可能在后续代码以不可控的方式结束。没人能够轻易判断究竟是哪里抛出了异常,以及是什么原因产生了异常。

try-catch-finally处理异常

try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行

  • 在finally语句块中发生了异常。
  • 在前面的代码中用了System.exit()退出程序。
  • 程序所在的线程死亡。
  • 关闭CPU。

try、catch、finally语句块的执行顺序:

  • 当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;

  • 当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;

  • 当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;

什么时候用到finally?
某些事务(除内存外)在异常处理完后需要恢复到原始状态, 如:开启的文件,网络的连接等。

Throw 和 Throws

throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throws语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。

throws主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。
throw是具体向外抛异常的动作,所以它是抛出一个异常实例。

throws说明你有那个可能,倾向。
throw的话,那就是你把那个倾向变成真实的了。

throws出现在方法函数头;
而throw出现在函数体。

throws表示出现异常的一种可能性,并不一定会发生这些异常;
throw则是抛出了异常,执行throw则一定抛出了某种异常。

两者都是消极处理异常的方式(这里的消极并不是说这种方式不好),只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

// 例1:throw 和 throws
public class ThrowEx {
    public void testThrowEx() {
        try {
            int a = 3 / 0;
        } catch (ArithmeticException e) {
            throw new MyException("除0异常");
        }
    }
    
    public void testThrowsEx() throws ArithmeticException {
        int a = 3 / 0;
    }
}

自定义异常

使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类RuntimeException即可
在程序中使用自定义异常类,大体可分为以下几个步骤:
(1)创建自定义异常类。
(2)在方法中通过throw关键字抛出异常对象。
(3)如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
(4)在出现异常方法的调用者中捕获并处理异常。

// 例2:自定义异常
public class MyException extends RuntimeException {
    private String myExceptionMsg;
    
    public MyException() {
        myExceptionMsg = "";
    }
    
    public MyException(String myExceptionMsg) {
        this.myExceptionMsg = myExceptionMsg;
    }

    public String getMyExceptionMsg() {
        return myExceptionMsg;
    }

    public void setMyExceptionMsg(String myExceptionMsg) {
        this.myExceptionMsg = myExceptionMsg;
    }
}

经典问题

  • NoClassDefFoundError 和 ClassNotFoundException 有什么区别?
    答:NoClassDefFoundError是一个错误(Error),而ClassNOtFoundException是一个异常。
    ClassNotFoundException是在编码的时候编译器就能告诉你这个地方需要捕获异常
    如:你使用Class.forName的时候就必须要你捕获或者throws这个异常。
    而NoClassDefFoundError在Javac已经把程序成功的编译成字节码文件了,当JVM进程启动,
    通过类加载器加载字节码文件,在classpath下找不到对应的类进行加载时就会发生NoClassDefFoundError这个错误。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值