https://www.dubby.cn/detail.html?id=9033

本篇文章主要给大家介绍一些众所周知的异常处理原则,但是也有部分鲜为人知,但也很有用的原则,希望能引发各位对异常处理的思考,以及在开发过程中,写出更优美的代码。

1.异常介绍

大致可以把异常分成三种情况下的异常(不正常情况):

  1. 代码错误引发的异常:比如数组越界,空指针等。
  2. 客户端错误调用引发的异常:比如用户名最长只允许32,客户端传了100;方法参数不能为空,客户端传了空等。
  3. 资源错误引发的异常:比如网络错误,硬盘故障,文件被删等。

2.Java中的异常介绍

无图言屌,下面就给出异常的继承关系图:

主要说说这几个概念:

  • Checked exceptions:这种异常在代码层面必须要捕获或者在签名处申明这个异常。这种异常是Java强制你必须捕获,因为这些一般一般是不可避免的,比如:网络,文件系统等不可控因素。
  • Unchecked exceptions:这种异常不会强制捕获或者在签名处申明。这类异常一般是由于代码问题产生的,比如:数组越界,空指针等。
  • Errors:这类错误,一般是在软件层面不可恢复的。比如:OutOfMemoryErrorLinkageError, 还有StackOverflowError。这种错误一般会是的程序(或者程序的一部分)不可用。针对这类错误,一定要有一个良好的日志习惯,不然很难定位。

3.自定义异常

一般我们想要自定义异常的目的都是为了让异常信息更丰富,比如:输入名称不合法,我们可能希望有一个UsernameInvalidException。本人在代码中曾经这么干过,一个类似的用法,好处很明显,在我们的内部监控系统中,对异常统计界面可以很清晰的反映出是什么问题,但是也带来一个问题,那就是异常数量很多。

在这里我先摆几个大师的意见吧:

  • 不要使用自定义异常:
    Java已经给我们提供了很多很多异常,尽量复用这些异常,好处有:减少我们的代码量,也就减少了维护的成本和精力,不至于让代码中出现很多只用过一次或几次的异常,最后异常数量爆炸(这就是我遇到的);使用通用异常,也可以减少别人阅读我们的代码,使用我们的接口时,更轻松,毕竟多一个类我们就需要理解这个类存在的意义。这里给几个经常可以用到的异常:
    1. IllegalStateException
    2. UnsupportedOperationException
    3. IllegalArgumentException
    4. NoSuchElementException
    5. NullPointerException
  • 如果不得不自定义异常,那就写个通用异常:
    如果自己不得不写的话,那就写的详细一下,不要只有个String来传达信息,那完全可以用通用的异常来替代,给个包含详细信息的例子:
  1. public class OutOfRangeException
  2. extends IllegalArgumentException {
  3. private final long value, min, max;
  4. public OutOfRangeException(long value, long min, long max) {
  5. super("Value " + value + " out of range " +
  6. "[" + min + ".." + max + "]");
  7. this.value = value;
  8. this.min = min;
  9. this.max = max;
  10. }
  11. public long getValue() {
  12. return value;
  13. }
  14. public long getMin() {
  15. return min;
  16. }
  17. public long getMax() {
  18. return max;
  19. }
  20. }

4.几个建议

1)不要生吞异常

  1. catch (NoSuchMethodException e) {
  2. return null;
  3. }

这样做会让这个异常信息永远的丢失,你将无法知道这个异常的原因,怎么去解决这个异常,甚至你不知道有这个异常的存在。

2)申明具体的异常

  1. public void foo() throws Exception { //不正确的做法
  2. }

这样除了告诉调用方我可能会有异常之外没有任何其他信息,而事实是我们本可以提供更具体的信息,建议这样做:

  1. public void foo() throws SpecificException1, SpecificException2 { //正确的做法
  2. }

3)尽可能的捕获具体异常

  1. try {
  2. someMethod();
  3. } catch (Exception e) {
  4. LOGGER.error("method has failed", e);
  5. }

这么做的问题是,如果你调用的方法中多了一个新的异常,他本来的目的是希望你处理这个新的异常,可是因为你在这里捕获了所有的异常,你可能会忽略这个提醒,而忘记捕获。

4)永远不要捕获Throwable

这样会捕获本来不该有我们来处理的错误,包括一些我们的代码无法处理的错误。

5)不要丢失异常信息

  1. catch (NoSuchMethodException e) {
  2. throw new MyServiceException("Some information"); //不正确
  3. }

这样做会完全丢失异常信息。

  1. catch (NoSuchMethodException e) {
  2. throw new MyServiceException("Some information: " + e.getMessage()); //不正确
  3. }

这种做法会丢失堆栈信息,建议:

  1. catch (NoSuchMethodException e) {
  2. throw new MyServiceException("Some information: " , e); //正确
  3. }

6)日志和上抛不可兼得

  1. catch (NoSuchMethodException e) {
  2. LOGGER.error("Some information", e);
  3. throw e;
  4. }

这样会导致一个问题,就是一个异常会有多份日志,因为上层可能也会记一次日志。所以要么上抛,要么记日志,不要都做。

7)不要在finally里抛异常

  1. try {
  2. someMethod(); //Throws exceptionOne
  3. } finally {
  4. cleanUp(); //If finally also threw any exception the exceptionOne will be lost forever
  5. }

这样的问题是,如果finally里也抛异常,就会导致真正的异常信息丢失,你只会收到finally里抛的异常。

8)不要为了捕获而捕获

  1. catch (NoSuchMethodException e) {
  2. throw e; //Avoid this as it doesn't help anything
  3. }

这段代码没有任何有意义,你可以直接上抛。

9)不要使用printStackTrace()或类似的语句

这种输出没有任何意义,而且不确定输出路径,对定位问题没有帮助。

10)不一定要catch

  1. try {
  2. someMethod(); //Method 2
  3. } finally {
  4. cleanUp(); //do cleanup here
  5. }

如果你只是想要finally来做善后,那就只用它就可以了,不要用catch。

11)“Throw early catch late”

这句话我不想翻译,因为我希望你能看到这句话,以后你也会见到这句话的。Throw early catch late。在底层抛异常,在信息足够的时候来捕获并处理。

12)记得用finall善后

比如数据库连接,一定要用finally关闭连接。当然你也可以用try-with-resource的方式。

13)上抛信息明确的异常

如果这个方法是解析文件,那么FileNotFoundException就比NullPointException更明确。

14)永远不要使用异常来做流程控制

  1. public void useExceptionsForFlowControl() {
  2. try {
  3. while (true) {
  4. increaseCount();
  5. }
  6. } catch (MaximumCountReachedException ex) {
  7. }
  8. //Continue execution
  9. }
  10. public void increaseCount()
  11. throws MaximumCountReachedException {
  12. if (count >= 5000)
  13. throw new MaximumCountReachedException();
  14. }

算我求你了,不要这么干!

15)尽早校验输入

很多异常都是由不合法的输入引起的,所以尽可能早的校验输入。

16)一条信息打印异常

  1. LOGGER.debug("Using cache sector A");
  2. LOGGER.debug("Using retry sector B");

何必呢?而且这样也容易误导其他人,建议:

  1. LOGGER.debug("Using cache sector A, using retry sector B");

17)让你的异常信息更充实

包括堆栈和其他提示信息。

18)如果线程被interrupted一定要结束线程

  1. while (true) {
  2. try {
  3. Thread.sleep(100000);
  4. } catch (InterruptedException e) {} //Don't do this
  5. doSomethingCool();
  6. }

这段代码很cool,但是一般会interrupt线程,要么是超时了,要么是线程池被关闭了,所以你应该尽可能的去结束线程。

19)使用模板来减少重复的try-catch代码

  1. class DBUtil{
  2. public static void closeConnection(Connection conn){
  3. try{
  4. conn.close();
  5. } catch(Exception ex){
  6. //Log Exception - Cannot close connection
  7. }
  8. }
  9. }

使用这个来减少每次都try一遍。

20)文档中加上异常说明

  1. /**
  2. * This method does something extremely useful ...
  3. *
  4. * @param input
  5. * @throws MyBusinessException if ... happens
  6. */
  7. public void doSomething(String input) throws MyBusinessException { ... }

前人种树后人乘凉,你可能也可以乘凉。

Java Exception最佳实践(转)的更多相关文章

  1. Atitit.嵌入式web 服务器 java android最佳实践

    Atitit.嵌入式web 服务器 java android最佳实践 1. Android4.4.21 2. 自己的webserver1 3. CyberHTTP for Java  cybergar ...

  2. Java异常处理最佳实践

    总结一些Java异常的处理原则 Java异常处理最佳实践 不要忘记关闭资源 在finally里关闭资源 public void readFile() { FileInputStream fileInp ...

  3. paip.myeclipse7 java webservice 最佳实践o228

    paip.myeclipse7  java webservice 最佳实践o228 java的ws实现方案:jax-ws>>xfire ws的测试工具  webservice测试调用工具W ...

  4. 10个精妙的Java编码最佳实践

    这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...

  5. 最重要的 Java EE 最佳实践

    參考:IBM WebSphere 开发人员技术期刊: 最重要的 Java EE 最佳实践 IBM WebSphere 开发人员技术期刊: 最重要的 Java EE 最佳实践 2004 年 IBM® W ...

  6. 你知道吗?10个精妙的 Java 编码最佳实践

    这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...

  7. Java异常处理最佳实践及陷阱防范

    前言 不管在我们的工作还是生活中,总会出现各种“错误”,各种突发的“异常”.无论我们做了多少准备,多少测试,这些异常总会在某个时间点出现,如果处理不当或是不及时,往往还会导致其他新的问题出现.所以我们 ...

  8. Java开发最佳实践(二) ——《Java开发手册》之"异常处理、MySQL 数据库"

    二.异常日志 (一) 异常处理 (二) 日志规约 三.单元测试 四.安全规约 五.MySQL数据库 (一) 建表规约 (二) 索引规约 (三) SQL语句 (四) ORM映射 六.工程结构 七.设计规 ...

  9. Java开发最佳实践(一) ——《Java开发手册》之"编程规约"

    Java开发手册版本更新说明 专有名词解释 一. 编程规约 (一) 命名风格 (二) 常量定义 (三) 代码格式 (四) OOP 规约 (五) 集合处理 (六) 并发处理 (七) 控制语句 (八) 注 ...

  10. .NET Core学习笔记(7)——Exception最佳实践

    1.为什么不要给每个方法都写try catch 为每个方法都编写try catch是错误的做法,理由如下: a.重复嵌套的try catch是无用的,多余的. 这一点非常容易理解,下面的示例代码中,O ...

随机推荐

  1. #Powerbi 1分钟学会利用AI,为powerbi报表进行高端颜色设计

    在BI报表的设计中,配色方案往往成为一大难题,一组切合主题.搭配合理的颜色设计往往能为我们的报表,加分不少. 今天,就介绍一个AI配色的网站,利用AI为pbi报表进行配色设计. 一:网站网址 http ...

  2. pip 更新

    pip install --user --upgrade pip成功升级

  3. 安装deb包

    输入命令: sudo dpkg  -i  file.deb

  4. Cilium系列-9-主机路由切换为基于 BPF 的模式

    系列文章 Cilium 系列文章 前言 将 Kubernetes 的 CNI 从其他组件切换为 Cilium, 已经可以有效地提升网络的性能. 但是通过对 Cilium 不同模式的切换/功能的启用, ...

  5. 开源流量检测引擎Dalton安装记录

    几个月之前照着官方文档安装过,一次性就成功,昨天重装了服务器再安装Dalton,怎么都安装不了 一直报错 ERROR: Service 'agent-suricata-current' failed ...

  6. 规范代码编写风格就用 eslint 和 prettier

    eslint 可以用于规范我们的编码,使得项目中的代码风格一致,更利于阅读和维护,而 prettier 可以在当我们代码不符合 eslint 规范是进行部分自动修复. eslint 通过 npm in ...

  7. 性能监控平台搭建(grafana+telegraf+influxdb) 及 配置 jmeter后端监听

    搞性能测试,可以搭建Grafana+Telegraf+InfluxDB 监控平台,监控服务器资源使用率.jmeter性能测试结果等. telegraf: 是一个用 Go 编写的代理程序,可收集系统和服 ...

  8. 使用在线Excel时,有哪些方法可以引入计算函数?

    摘要:本文由葡萄城技术团队于博客园原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 在日常生活和工作中,我们都会或多或少的使用Excel中的 ...

  9. 《深入理解Java虚拟机》读书笔记:Class类文件的结构

    Class类文件的结构 Sun公司以及其他虚拟机提供商发布了许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的的程序存储格式--字节码(ByteCode),从而实现了程序 ...

  10. 在 Visual Studio 2022 中使用文件对比

    在最新版本的 Visual Studio 2022 中,加入了新的功能特性--"文件对比". 在开发过程中,开发人员有时会需要比对文件差异,特别是代码文件,之前很多时候是借助版本控 ...