谈谈Java异常处理这件事儿
此文已由作者谢蕾授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
前言
我们对于“异常处理”这个词并不陌生,众多框架和库在异常处理方面都提供了便利,但是对于何种处理才是最佳实践,也是众说纷纭。异常处理是否得当直接关系到软件的健壮性,今天就谈谈我对异常处理这件事儿的拙见。首先,先说一下异常处理的通俗解释:当危险或知道事情不对的时候做出的反馈。
目录结构
Java的异常分类
常见的异常处理的方法
推荐的实践方式
1. Java的异常分类
先简单用图介绍一下Java的异常分类:
JAVA这种面向对象的语言,同样把异常当作对象来处理,Throwable作为所有异常的超类,然后定义了许多异常类,将这些异常类分为两大类:错误Error和异常Exception。其中,Exception异常类又分为RuntimeException和Checked Exception(也叫非运行时异常)。 Error是程序无法处理的错误,比如OutofMemoryError、TheadDeath等。Exception是程序本身可以处理的异常,应当尽可能去处理这些异常。运行时异常都是RuntimeException类及其子类异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理,如NullPointerException。通常,这些异常一般是由错误代码逻辑引起的,我们应该从逻辑角度尽可能避免这类异常的发生。 非运行时异常从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException 、SQLException等以及用户自定义的异常,一般情况下不自定义运行时异常。
2. 常见的异常处理方法
根据Java工程分层的思想,异常处理也是基于分层的思想。每层都和他的上下层之间都有一个契约,契约内容中就包含了异常处理。任何一层都可能遇到不测,如果遇到了未知的错误,不知道如何处理时,通常的做法就是愉快的向上层抛出一个异常,渴求有一层能正确处理掉这个可怜的错误。我们常用的Java异常处理机制通常依赖于try、catch、finally、throw、throws。 常见的异常处理方式如下:
吞掉并抛出
打印log并抛出
嵌套处理并抛出
忽略异常
2.1 吞掉并抛出
try{
...
}catch(Exception e){throw new ApiException(ApiErrorCode.SqlErr, "Failed to get JobID.");
}
注:ApiException是程序自定义的异常,与SQLEXCEPTION、RUNTIMEEXCEPTION等都属于异常的一种。 比较明显,这种处理方式导致丢失了真实的错误信息,不利于上层做出正确的处理。非常不好的实践。
2.2 打印log并抛出
try{
boolean ret = sendNotify(info);
if(ret){
i.remove();
}
}catch(ParseException | IOException e){
logger.error("unexpected exception happened while send notify to client! remove notify message! jobID: " + info.getJobID(), e);
throw e;
}
这个做法想必大家经常看到,在许多工程中都用了这样的做法。但是这样的处理方式也在一定环境下也有问题,比如,当异常发生在调用层次较深的底层时,同样的错误信息处理方式,会导致我们为了定位问题将看到无数的相同错误信息。所以,具体的异常处理方法还需要综合上下文来处理。
2.3 嵌套处理并抛出
try{
...
}catch(SQLException e){throw new XxxException("Error in Xxx", e);
}
这段代码catch住了sql异常,然后将其封装为另外一种异常抛出,期望遇到知心人能读懂它的良苦用心。
2.4 忽略异常
try{
...
}catch(SQLException ex){
ex.printStacktrace();
}
经常看到这样的低级错误吗?是的,开发者无情的忽略了异常,并且只把异常信息输出到控制台,然后,程序仍然继续运行,非常有可能导致更多的异常。
3.推荐的实践方式
此节不敢称为最佳实践,因为一切都会随着空间和时间的变化而变化。只能说下笔者见过的对异常处理的一些推荐做法。如有不适当的地方,请大家指正。
如果不知道如何处理异常,最好在定义方法时throws该异常,可以声明多个异常。
细化异常,尽可能的指定具体的异常,方便问题定位,尽量不要使用范围太大的Exception。但是,有时一定要最大范围捕获的,比如一些线程不想让它意外退出,那就必须通过最外层捕获它了。
避免过大的try块(对所有可能出现异常的代码进行try块的包装),这样不利于分析问题产生的原因。
一个try对应多个catch时,catch的异常定义可以由精确到一般。
不要无视捕获的异常,小心因小失大。捕获到后要么直接抛出,要么重新抛出新类型的异常。
不要在finally块中return或throw等终止方法的语句,这样会导致try或catch块中的return或throw失效。
鼓励程序适时的进行自定义异常类(非检测异常的一种),因为异常的类名往往包含了很多有用信息,我们封装后的异常类可以更加具体的根据代码或业务处理区分异常类型,方便查找错误。
调试时可以使用printStackTrace()方法,但是发布后要避免使用该方法。
管理好自己和其他层之间的异常处理,契约精神,注意:不要把自己能处理的异常抛给别人。
网易云免费体验馆,0成本体验20+款云产品!
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 HashMap在并发场景下踩过的坑
谈谈Java异常处理这件事儿的更多相关文章
- 谈谈你对Java异常处理机制的理解
先谈谈我的理解:异常处理机制可以说是让我们编写的程序运行起来更加的健壮,无论是在程序调试.运行期间发生的异常情况的捕获,都提供的有效的补救动作,任何业务逻辑都会存在异常情况,这时只需要记录这些异常情况 ...
- “崩溃了?不可能,我全 Catch 住了” | Java 异常处理
前言 今天我们来讨论一下,程序中的错误处理. 在任何一个稳定的程序中,都会有大量的代码在处理错误,有一些业务错误,我们可以通过主动检查判断来规避,可对于一些不能主动判断的错误,例如 RuntimeEx ...
- 札记:Java异常处理
异常概述 程序在运行中总会面临一些"意外"情况,良好的代码需要对它们进行预防和处理.大致来说,这些意外情况分三类: 交互输入 用户以非预期的方式使用程序,比如非法输入,不正当的操作 ...
- 《转载》Java异常处理的10个最佳实践
本文转载自 ImportNew - 挖坑的张师傅 异常处理在编写健壮的 Java 应用中扮演着非常重要的角色.异常处理并不是功能性需求,它需要优雅地处理任何错误情况,比如资源不可用.非法的输入.nul ...
- Java提高篇——Java 异常处理
异常的概念 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少了一个分号,那么运行出来结果是提示是错误java.lang.Error:如果你用Syst ...
- 谈谈Java程序员进阶的那些知识和方向
谈谈Java程序员进阶的那些知识和方向 记得前段时间看过一篇文章谈到一种程序员叫野生程序员,战斗力极强,可以搞定一切问题,但是通常看问题抓不到本质,或者说是google/baidu/stackover ...
- Java日志框架那些事儿
文章首发于[博客园-陈树义],点击跳转到原文Java日志框架那些事儿. 在项目开发过程中,我们可以通过 debug 查找问题.而在线上环境我们查找问题只能通过打印日志的方式查找问题.因此对于一个项目而 ...
- Java异常处理的10个最佳实践
本文作者: ImportNew - 挖坑的张师傅 未经许可,禁止转载! 异常处理在编写健壮的 Java 应用中扮演着非常重要的角色.异常处理并不是功能性需求,它需要优雅地处理任何错误情况,比如资源不可 ...
- Java异常处理的9个最佳实践
无论你是新手还是资深程序员,复习下异常处理的实践总是一件好事,因为这能确保你与你的团队在遇到问题时能够处理得了它. 在 Java 中处理异常并不是一件易事.新手觉得处理异常难以理解,甚至是资深开发者也 ...
随机推荐
- TYOI Day1 travel:Tree dp【处理重复走边】
题意: 给你一棵树,n个节点,每条边有长度. 然后有q组询问(u,k),每次问你:从节点u出发,走到某个节点的距离mod k的最大值. 题解: 对于无根树上的dp,一般都是先转成以1为根的有根树,然后 ...
- Guid 使用记录
Guid 使用记录; Guid 数据不能设为null 用 00000000-0000-0000-0000-000000000000 代替默认值. 实体新建时,可以赋值为 Guid.Empty 也就是 ...
- linux系统配置之单一网卡配置多个不同网段IP(centos)
1.用root权限的用户登录CENTOS,进入network-scripts文件夹下(本步骤可以省略,与二步骤一起完成): shell命令:cd /ect/sysconfig/network-scri ...
- Java中数学计算的相关方法
1:Math类 2.BigInteger类 3.BigDecimal类 BigInteger bi = new BigInteger("12433241123"); BigDec ...
- Nginx+ffmpeg的HLS开源服务器搭建配置及开发详
本文概述: 至目前为止,HLS 是移动平台上非常重要并十分流行的流媒体传输协议.做移动平台的流媒体开发,不知道它不掌握它 ,真是一大遗憾.而HLS的平台搭建有一定的难度,本文针对对该方向有一定了解的朋 ...
- RTP Payload Format for Opus Speech and Audio Codec
[Docs] [txt|pdf] [Tracker] [WG] [Email] [Diff1] [Diff2] [Nits] Versions: (draft-spittka-payload-rtp- ...
- SHOI2016 随机序列
给你一个数列,在相邻两个数之间插入加号,减号或乘号 每次支持单点修改,求所有这样可以得到的表达式之和,膜1e9 + 7 sol: 我是个 sb ... 可以发现,如果某位置出现了加号,后面一定有一个减 ...
- 每天一个linux命令(10):touch命令
版权声明更新:2017-05-14博主:LuckyAlan联系:liuwenvip163@163.com声明:吃水不忘挖井人,转载请注明出处! 1 文章介绍 本文介绍了Linux下面的mv命令. 2. ...
- ACM学习历程—HDU4675 GCD of Sequence(莫比乌斯)
Description Alice is playing a game with Bob. Alice shows N integers a 1, a 2, …, a N, and M, K. She ...
- bzoj 4766: 文艺计算姬 矩阵树定理
题目: 给定一个一边点数为\(n\),另一边点数为\(m\),共有\(n*m\)条边的带标号完全二分图\(K_{n,m}\) 计算其生成树个数 \(n,m,p \leq 10^{18} ,p为模数\) ...