zoukankan      html  css  js  c++  java
  • Exception与error的区别

    Error和Exception都是继承了Throwable类,Java里面只有Throwable实例才可以抛出(throw)和捕捉(catch)异常。Error和Exception是对不同异常情况的分类,

    1.Error:

    1) 是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如 OutOfMemoryError 之类,都是 Error 的子类。
    2)Error就是Java运行时内部错误与资源耗尽错误,这种内部错误一旦出现,除了告知用户并使程序安全终止之外,在无能为力,断电。
    2.Exception(程序出错):

    Exception 又分为受查(checked)异常和不受查(unchecked)异常,可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。前面我介绍的不可查的 Error,是Throwable 不是 Exception。不检查异常就是所谓的运行时异常,类似 NullPointerException、ArrayIndexOutOfBoundsException 之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求
    Exception是程序正常运行过程中,可以预料的异常情况,可以对他们进行捕捉,并进行相应的处理
    1)? IOException:程序本身没有问题,由于IO处理程序导致出错

    2)? ?RuntimeException:经常性出现的错误,可以捕获,并作出处理,可以不捕获,也可以不用抛出。? ? ? ? ? ? ? ? ? ? ?ArrayIndexOutOfBoundsException像:这种异常可以不捕获,为什么呢?在一个程序里,使用很多数组,如果使用一次捕获一次,则很累。

    非受查异常:由于继承与Error或RuntimeException(空指针,类型转换)的异常类称为非受查异常

    受查异常(必须强制处理):所有继承Exception与IOException的称为受查异常

    ?

    3.异常处理格式

    try{

    ???????可能出现异常的语句

    }[catch??( 异常类 对象??) ]??{

    ????出现异常的操作

    }[finaly ]{

    ????异常的出口(无论是否产生异常,都会走finaly,并且是最后走)

    }
    try....catch...

    try....finaly....

    try.....catch....finaly....

    无论是否产生异常,无论try ,catch是否有返回语句,最终都会执行finaly块,Lock锁的释放,JDBC里数据库的关闭,

    try catch finally的执行流程

    1.不管有没有出现异常,finally块中代码都会执行;
    2.当try和catch中有return时,finally仍然会执行;当finally里面没有return语句是,执行try 和finally语句之后最后再执行return。?
    3.finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
    4.finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
    注意:

    仅仅在下面4中情况下不会执行finally语句 :

    如果在try 或catch语句中执行了System.exit(0)。
    .在执行finally之前jvm崩溃了。
    .try语句中执行死循环。
    .电源断电。
    https://blog.csdn.net/u013309870/article/details/73498860里面讲解了try catch finally的执行流程

    throw和throws关键字

    1.throws关键字---作用于方法上

    在进行方法定义时,如果要明确告诉调用者本方法可能会产生那些异常,可以用throws方法进行声明,表示将异常抛回给回调方,并且当方法出现问题后可以不处理异常
    ?

    2.throw关键字--作用在方法中

    throw语句直接写在方法中,表示人为进行异常抛出。一般与自定义异常类搭配使用。
    如果现在异常类对象实例化不希望由JVM产生而由用户产 生,就可以使用throw来完成
    断言assert

    assert是一个布尔表达式,是一个Error异常

    ?

    知识扩展:

    1.分析下面代码的问题

    try {
    // 业务代码
    // …
    Thread.sleep(1000L);
    } catch (Exception e) {
    // Ignore it
    }
    第一个问题:它捕捉的是Exception异常,这是异常的父类,他应该捕捉特定的异常,而不是通用的异常。

    这里Thread.sleep() 抛出的 InterruptedException异常,其他情况下也会有类型转换异常,空指针异常,数组越界异常等。所以捕捉的异常尽量要细,而不是抛出一个Exception。这样做的目的就是能够直接的体现出更多而信息,而Exception却隐藏了这些信息,同时我们也要保证程序不会捕捉到我们不希望捕捉的异常,比如RuntimeException。
    一般情况下不要捕捉Throwable和Error,因为很难保证我们能够正确的处理OutOfMemoryError,
    ?

    第二个问题:不要生吞异常,这是异常处理中要特别注意的事情,因为很可能会导致非常难以诊断的诡异情况。

    生吞异常(掩盖问题):往往是基于假设这段代码可能不会发生,或者感觉忽略异常是无所谓的,但是千万不要在产品代码做这种假设!
    如果我们不把异常抛出来,或者也没有输出到日志(Logger)之类,程序可能在后续代码以不可控的方式结束。没人能够轻易判断究竟是哪里抛出了异常,以及是什么原因产生了异常。这回导致发现异常和处理异常变得非常困难。
    ?

    2.分析该段代码的问题

    e.printStackTrace();

    一个catch可能解决不了所有的问题,所以用catch(Exception e){e.PrintStackTrace}

    try {
    // 业务代码
    // …
    } catch (IOException e) {
    e.printStackTrace();
    }
    在printStackTrace()的文档,开头就是“Prints this throwable and its backtraceto the standard error stream”。问题就在这里,在稍微复杂一点的生产系统中,标准出错(STERR)不是个合适的输出选项,因为你很难判断出到底输出到哪里去了。
    尤其是对于分布式系统,如果发生异常,但是无法找到堆栈轨迹(stacktrace),这纯属是为诊断设置障碍。所以,最好使用产品日志,详细地输出到日志系统里。
    从性能角度来审视一下 Java 的异常处理机制,这里有两个可能会相对昂贵的地方:

    try-catch 代码段会产生额外的性能开销,或者换个角度说,它往往会影响 JVM 对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的 try 包住整段的代码;与此同时,利用异常控制代码流程,也不是一个好主意,远比我们通常意义上的条件语句(if/else、switch)要低效
    Java 每实例化一个 Exception,都会对当时的栈进行快照,这是一个相对比较重的操作。如果发生的非常频繁,这个开销可就不能被忽略,所以,对于部分追求极致性能的底层类库,有种方式是尝试创建不进行栈快照的 Exception。这本身也存在争议,因为这样做的假设在于,我创建异常时知道未来是否需要堆栈.问题是,实际上可能吗?小范围或许可能,但是在大规模项目中,这么做可能不是个理智的选择.如果需要堆栈,但又没有收集这些信息,在复杂情况下,尤其是类似微服务这种分布式系统,这会大大增加诊断的难。当我们的服务出现反应变慢、吞吐量下降的时候,检查发生最频繁的 Exception 也是一种思路。
    Throw early, catch late 原则

    public void readPreferences(String fileName){
    //...perform operations...
    InputStream in = new FileInputStream(fileName);
    //...read the preferences file...
    }
    这里如果fileName 是 null,那么程序就会抛出 NullPointerException,但是由于没有第一时间暴露出问题,堆栈信息可能非常令人费解,往往需要相对复杂的定位。这个 NPE 只是作为例子,实际产品代码中,可能是各种情况,比如获取配置失败之类。在发现问题的时候,第一时间抛出,能够更加清晰地反映问题。

    所以,修改代码,即throw early

    public void readPreferences(String filename) {
    Objects. requireNonNull(filename);
    //...perform other operations...
    InputStream in = new FileInputStream(filename);
    //...read the preferences file..
    }
    关于“catch late”,其实经常苦恼的问题,是捕获异常后,需要怎么处理呢?最差的处理方式,就是我前面提到的“生吞异常”,本质上其实是掩盖问题。如果实在不知道如何处理,可以选择保留原有异常的 cause 信息,直接再抛出或者构建新的异常抛去。在更高层面,因为有了清晰的(业务)逻辑,往往会更清楚合适的处理方式是什么。

    ?

    自定义异常需要考虑的问题

    是否需要定义成 Checked Exception,因为这种类型设计的初衷更是为了从异常情况恢复,作为异常设计者,应该具有充足信息进行分类。
    在保证诊断信息足够的同时,也要考虑避免包含敏感信息,因为那样可能导致潜在的安全问题。如果我们看 Java 的标准类库,你可能注意到类似 java.net.ConnectException,出错信息是类似“ Connection refused (Connection refused)”,而不包含具体的机器名、IP、端口等,一个重要考量就是信息安全。类似的情况在日志中也有,比如,用户数据一般是不可以输出到日志里面
    当然这里面也由两个问题:

    Checked Exception 的假设是我们捕获了异常,然后恢复程序.但是,其实大多数情况下,根本就不可能恢复.Checked Exception 的使用,已经大大偏离了最初的设计目的.
    Checked Exception 不兼容 functional 编程,如果你写过 Lambda/Stream 代码,相信深有体
    -!
  • 相关阅读:
    leetcode33. Search in Rotated Sorted Array
    pycharm 设置sublime text3 monokai主题
    django class Meta
    leetcode30, Substring With Concatenation Of All Words
    Sublime text3修改tab键为缩进为四个空格,
    sublime text3 python打开图像的问题
    安装上imesupport输入法依然不跟随的解决办法,
    sublime text3 的插件冲突弃用问题,
    sublime text3 BracketHighlighter括号匹配的设置
    windows 下wget的使用
  • 原文地址:https://www.cnblogs.com/hetaoyuan/p/11325085.html
Copyright © 2011-2022 走看看