response.end后抛了异常_月薪3万以上的程序员必备技能:Java 中的异常和处理详解...

处理异常需要解决的问题

  • 哪里发生异常?

可以通过try-catch捕获异常。不建议用try-catch捕获大代码块,同时捕获异常时要分清稳定代码(无论如何都不会出错的代码,如int i = 0)和非稳定代码(有可能出错的代码。如:Integer.valueOf(String s)转换失败时抛出NumberFormatException异常)。

  • 谁来处理异常?
  • throw:用于方法内抛出具异常类对象的关键字。

b3bbf400508117ec9ccc0ec59fc25bf8.png

throws:用在方法签名上,表示方法调用者可以通过此方法声明向上抛出异常对象。

077669b684ce7067875af6d992d8a73c.png

如果异常在当前方法处理能力范围之内则没必要对外透出,直接捕获并做相应处理即可。否则向上抛出,由上层方法或框架来处理。

  • 如何处理异常?

禁止异常捕获后什么都不做或打印一行日志了事

  • 方法内处理:需要根据业务场景定制处理,如重试、回滚等操作。
  • 向上抛异常:需要在异常对象中添加上下文参数、局部变量、运行环境等信息,有利于排查问题。

异常分类

JDK中定义了一套完整的异常机制, 所有异常都是Throwable的子类分为Error(致命异常)和Exception(非致命异常)。Error是一种非常特殊的异常类型(程序无法处理,只能人工介入),它的出现标识着系统发生了不可控的错误,如StackOverflowError、OutOfMemoryError。 Exception又分为checked异常(受检异常)和unchecked(非受检异常)
  • checked异常需要在代码中显式处理的异常,否则会编译出错。如:SQLException、ClassNotFoundException等。checked异常又可细分为:
    • 无能为力、引起注意型。即程序无法处理,如字段超长等导致的SQLException。处理方式:保存异常现场,工程师介入。
    • 力所能及、坦然处置型。如发送未授权异常,程序可以直接跳转至权限申请页面。
  • unchecked异常运行时异常,都继承自RuntimeException,不需要显式的捕获和处理。unchecked异常又可细分为:
    • 可预测异常:包括IndexOutOtBoundsException、NullPointerException等异常。基于代码性能和稳定性考虑,此类异常不应该被产生或抛出,应该提前做好边界检查、空指针判断等处理
    • 需捕捉异常:如使用Dubbo框架RPC调用产生的远程调用超时异常DubboTimeoutException,客户端必须显式处理(重试、降级处理等),不能因为服务器异常导致客户端不可用。
    • 可透出异常:指框架或系统产生的且会自行处理的异常,而程序无须关心。

异常分类结果图如下:

12c1163d3e0455a67108169895f9a619.png

最后,处理异常时,要明确该异常属于哪种异常类型,是需要调用方关注并处理的checked异常,还是由更高层次框架处理的unchecked异常。无论哪类异常,如果需要向上抛出,推荐根据当前场景自定义具有业务含义的异常。(不推荐直接使用RuntimeException、Exception等没有业务含义的异常类,同时为了避免异常泛滥,推荐优先使用业界或团队定义过的异常

try代码块

try-catch-finally是处理异常的三部剧。当存在 try 时,可以只有 catch 代码块, 也可以只有 finally 代码块,就是不能单独只有 try 这个光杆司令。
  • try代码块: 监视代码执行过程,一旦发现异常则直接跳转至catch,如果没有catch,则直接跳转至finally。
  • catch代码块: 可选执行代码,如果没有任何异常发生则不会执行;如果发现异常则可以在catch代码块中进行处理或向上抛出。
  • finally代码块: 必须执行代码块不管是否发生异常,即使发送OutOfMemoryError也会执行。通常用于处理善后清理工作。finally代码块没有执行的三种可能(很多恶心的面试官会问)
  • 没有进入try代码块。
  • 进入try代码块,但是代码运行中出现死循环或死锁状态。
  • 进入try代码块。但是执行了System.exit()操作。

注意: finally是在return表达式运行后执行的,此时return的结果已经被缓存起来,待finally代码块执行结束后再将之前暂存的结果返回。示例代码如下:

f214e5a5c9a212e3bb5e60c6965baf68.png

禁止finally代码块中使用return语句。因为在finally中使用return会使得返回值的判断变得复杂,不可控。

try代码块与锁关系:

44305760c9820d500718c2927ff993ad.png

cc680a389a04a5e27a219e9b5d76dbed.png

最后:Lock、ThreadLocal、InputStream 等这些需要进行强制释放和清除的对象都得在 finally 代码块中进行显式的清理,避免产生内存泄漏或资源消耗。

异常的抛与接

传递异常信息的方式是通过抛出异常对象,还是把异常信息转成信号量封装在特定对象中,这需要方法提供者和方法调用者之间达成契约,只有大家都照章办事,才不会产出误解。 推荐对外提供的开放接口使用错误码,公司内部跨应用远程服务调用优先考虑使用 Result 对象来封装错误码、错误描述信息;而应用内部则推荐直接抛出异常对象。

方法是否直接返回null: 不强制直接返回空集合或者空对象等,但是必须添加注释充分说明什么情况下会返回null值。防止NPE一定是调用方的责任,需要调用方进行事先判断。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值