面试——了解异常

异常的分类

假如你开车上山,车坏了,你拿出工具箱修一修,修好继续上路(Exception被捕获,从异常中恢复,继续程序的运行),
车坏了,你不知道怎么修,打电话告诉修车行,告诉你是什么问题,要车行过来修。
(在当前的逻辑背景下,你不知道是怎么样的处理逻辑,把异常抛出去到更高的业务层来处理)。
你打电话的时候,要尽量具体,不能只说我车动不了了。那修车行很难定位你的问题。(要捕获特定的异常,不能捕获类似Exception的通用异常)。
还有一种情况是,你开车上山,山塌了,这你还能修吗?(Error:导致你的运行环境进入不正常的状态,很难恢复)
参看图:

Exception和Error都是继承了Throwable类,在Java中也只有Throwable类型的实例才可以被抛出或者捕获
Error描述了Java运行时系统内部错误和资源耗尽错误,不需要也不便于捕获。
Exception分为检查型(checked)异常和非检查型(unchecked)异常
checked异常必须显式进行捕获处理,属于编译期检查的一部分
unchecked异常就是运行时异常。

2、基本语法
try-catch-finally块,throw,throws关键字
在finally里做一些资源回收工作
try-with-resources,multiple catch
或自定义扩展AutoCloseable或者Closeable的对象

3、捕获异常的基本原则
  1)、尽量不要捕获类似Exception这样通用异常,应该捕获特定异常。
    原因:这样的异常捕获不能反应更多的信息

  2)、不要生吞异常
    原因:导致问题诊断变得麻烦
    printStackTrace()输出(STERR),无法确定输出到哪里,最好使用产品日志,详细输出到日志系统

  3)Throw early,catch late原则

public void readPreferences(String fileName){
     //...perform operations... 
    InputStream in = new FileInputStream(fileName);
     //...read the preferences file...
}

如果fileName是null,那么程序就会抛出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信息,或者再抛出或者构建新的异常抛出去。

自定义异常应该保证诊断信息足够的同事,避免敏感信息。

4、异常的性能问题
  try-catch代码段会产生额外的性能开销,原因是影响JVM对代码的性能调优,尽量不要用大的try包住整段的代码
  利用异常控制代码流程,也不是个好主意,比条件语句(if/else,switch)要低效。

  java每实例化一个Exception,就会对当时栈进行快照,如果发生比较频繁,开销就比较大

5、异常进阶
  异常:这种情况下的异常,可以通过晚上任务充实机制,在执行异常时,保存当前任务信息加入重试队列,重试的策略
    根据业务需求决定,当达到重试上限依然无法成功,记录任务执行失败,同时发出警告。
  日志:类比消息中间件,处在不同线程之间的同一个任务,简单高效做法是用traceId/requestId串联,有些日志支持MDC/NDC功能,可以串联相关联日志

6、阿里规约看异常

 

posted @ 2018-10-23 20:36  一心行走  阅读(203)  评论(0编辑  收藏  举报