因为代码经验和见识等原因,说实话现在对于异常的使用,我也算是理解甚少。为什么用?什么时候用?即便是在查阅了部分资料以后,也只能在这里提炼出部分自己能够理解的,以供参考和讨论。

1、使用异常的好处

1.1 隔离常规代码和错误处理代码

实际上,我们希望程序不要出现问题,用户操作永远逻辑清晰而正确,一切都按照我们祈祷的那样运行,然而这是不可能的。必然会有错误必然会要我们去处理,但是错误的处理并不是我们代码的核心。
就像用户取钱的操作,我们核心的代码应该是账户金额变动和更新,而过程中可能出现的各种意外如余额不足,取钱超出额度等夹杂在我们的正常逻辑里,代码必然显得混乱,可读性差。而异常机制将这些意外情况剥离了出来。
我们用个简单的例子来说明:
//假如我们要实现将一个文件读入内存,实际上真正核心只需要下面5步
readFile {open the file;determine its size;allocate that much memory;read the file into memory;close the file;
}
8
1
//假如我们要实现将一个文件读入内存,实际上真正核心只需要下面5步  

2
readFile {

3
    open the file;

4
    determine its size;

5
    allocate that much memory;

6
    read the file into memory;

7
    close the file;

8
}

//为了处理文件不能打开、不能确定文件大小、内存分配不足等可能出现的意外,我们可能最终写成如下
errorCodeType readFile {initialize errorCode = 0;open the file;if (theFileIsOpen) {determine the length of the file;if (gotTheFileLength) {allocate that much memory;if (gotEnoughMemory) {read the file into memory;if (readFailed) {errorCode = -1;}} else {errorCode = -2;}} else {errorCode = -3;}close the file;if (theFileDidntClose && errorCode == 0) {errorCode = -4;} else {errorCode = errorCode and -4;}} else {errorCode = -5;}return errorCode;
}
31
1
//为了处理文件不能打开、不能确定文件大小、内存分配不足等可能出现的意外,我们可能最终写成如下

2
errorCodeType readFile {

3
    initialize errorCode = 0;

4
   

5
    open the file;

6
    if (theFileIsOpen) {

7
        determine the length of the file;

8
        if (gotTheFileLength) {

9
            allocate that much memory;

10
            if (gotEnoughMemory) {

11
                read the file into memory;

12
                if (readFailed) {

13
                    errorCode = -1;

14
                }

15
            } else {

16
                errorCode = -2;

17
            }

18
        } else {

19
            errorCode = -3;

20
        }

21
        close the file;

22
        if (theFileDidntClose && errorCode == 0) {

23
            errorCode = -4;

24
        } else {

25
            errorCode = errorCode and -4;

26
        }

27
    } else {

28
        errorCode = -5;

29
    }

30
    return errorCode;

31
}

如此我们得到的是混乱糟糕的代码,可读性极差,将来一旦出现需要维护的情况,更是苦不堪言。而当我们使用异常机制来处理时,清晰的处理逻辑和代码可读性不言而喻:
readFile {try {open the file;determine its size;allocate that much memory;read the file into memory;close the file;} catch (fileOpenFailed) {doSomething;} catch (sizeDeterminationFailed) {doSomething;} catch (memoryAllocationFailed) {doSomething;} catch (readFailed) {doSomething;} catch (fileCloseFailed) {doSomething;}
}
19
1
readFile {

2
    try {

3
        open the file;

4
        determine its size;

5
        allocate that much memory;

6
        read the file into memory;

7
        close the file;

8
    } catch (fileOpenFailed) {

9
      doSomething;

10
    } catch (sizeDeterminationFailed) {

11
        doSomething;

12
    } catch (memoryAllocationFailed) {

13
        doSomething;

14
    } catch (readFailed) {

15
        doSomething;

16
    } catch (fileCloseFailed) {

17
        doSomething;

18
    }

19
}

(笔者:如上例所有核心代码都用try包裹,确实代码清晰;而事实上倡导的是尽量减小try块,我个人在写一些涉及到IO的方法时,代码经常因为这个原则被try-catch分割得七零八落,基本上和使用if-else无差,所以个人认为try块对于代码的粒度控制,不必完全基于尽量最小的原则,毕竟同时try-catch的性能影响微乎其微)

1.2 延迟处理

throws关键字的使用,使得可能出现的错误不必在当前逻辑中立即处理,而是留待给它的调用者来处理。
因为很多时候,某些底层方法是不知道要如何去处理这些错误的,而只有业务层根据实际的业务逻辑和需求,才知道如何处理,比如业务层可能会将错误信息显示给用户,以起提示和引导操作。
实际上,也可以选择层层抛出的方式,即“ catch语句中处理异常后,再次throw抛出该异常 ”,继续抛出异常可使得调用方法能够再次获得并处理异常。比如程序员可以在底层方法中抓到异常后,打印错误日志以供开发者查看,同时再次抛出给上层调用者,以便业务层调用时使用,如显示错误信息给用户。
同时,受检类型的异常也起到了提醒的作用,告知调用者这个方法可能发生异常,那么你必须进行捕获并考虑处理。

1.3 异常的精确定位

com.test9.MyException: 文件没有找到--02at com.test9.Test.g(Test.java:31)at com.test9.Test.main(Test.java:38)
Caused by: com.test9.MyException: 文件没有找到--01at com.test9.Test.f(Test.java:22)at com.test9.Test.g(Test.java:28)... 1 more
Caused by: java.io.FileNotFoundException: G:\myfile\struts.txt (系统找不到指定的路径。)at java.io.FileInputStream.open(Native Method)at java.io.FileInputStream.<init>(FileInputStream.java:106)at java.io.FileInputStream.<init>(FileInputStream.java:66)at java.io.FileReader.<init>(FileReader.java:41)at com.test9.Test.f(Test.java:17)... 2 more
1
com.test9.MyException: 文件没有找到--02

2
    at com.test9.Test.g(Test.java:31)

3
    at com.test9.Test.main(Test.java:38)

4
Caused by: com.test9.MyException: 文件没有找到--01

5
    at com.test9.Test.f(Test.java:22)

6
    at com.test9.Test.g(Test.java:28)

7
    ... 1 more

8
Caused by: java.io.FileNotFoundException: G:\myfile\struts.txt (系统找不到指定的路径。)

9
    at java.io.FileInputStream.open(Native Method)

10
    at java.io.FileInputStream.<init>(FileInputStream.java:106)

11
    at java.io.FileInputStream.<init>(FileInputStream.java:66)

12
    at java.io.FileReader.<init>(FileReader.java:41)

13
    at com.test9.Test.f(Test.java:17)

14
    ... 2 more

如果采用 if-else-print 的方式在控制台打印错误信息,以达到出错时提示的目的,那么在debug时无疑是不如异常机制的,如上图例可以看到,使用异常机制,一旦出现异常,控制台不光有提示,更精确定位了出错的代码位置。
编程5分钟,找虫2小时,善用异常机制能够节约不少调试的时间。

2、异常使用的注意事项

  • 异常捕获后不做任何处理,就是耍流氓,挖坑埋自己
  • 异常机制不要用来做流程或条件控制,因为处理效率较低
  • try-catch若不触发catch是不影响性能的,但是try块仍然不要滥用包裹大量代码 (详见参考链接中相关文章)
  • 方法出错该抛异常就抛异常,而不是返回一些错误码

3、参考链接

  • 使用异常的优势
  • 如何正确使用Java异常处理机制
  • 浅析Java异常机制
  • Java上的try catch并不影响性能
  • Java程序猿必须懂的一些异常处理指引

4、异常方面的教训记录

4.1 关于try-catch和自定义Exception

因为知道try块不触发异常并不影响性能,于是我个人为了代码更好的可读性,扩大了try块的范围。后来便给自己造成了一点麻烦的事就是,假如:A底层方法抛出异常,B调用A时会捕获异常并打印信息,然后再次抛出该异常以供调用者使用。
于是我在调用B时要求处理异常,为了便于异常信息的使用,我到B的代码中去看是哪里抛出的异常,结果try块太庞大几乎包裹了所有代码,以至于我无法判断真正抛出异常的A在B中代码的哪个部分。所以try块也不能滥用。
另外,自定义异常的范围不明确,这才以至于我需要追踪到底层去判断捕获的异常如何处理,是内部记录还是做弹窗给用户提示?所以自定义异常的命名和创建也是需要明确范围和目的,是哪种类型的业务就建相应的异常,而不要一股脑就单独一个BusinessException。

转载于:https://www.cnblogs.com/deng-cc/p/7462539.html

[03] 为什么要使用异常机制相关推荐

  1. Python培训教程分享:Python异常机制

    ​ 在学习Python技术的时候,我们经常会遇到一些异常,例如导致程序在运行过程中出现的中断或退出,我们都称之为异常,大多数的异常都不会被程序处理,而是以错误信息的形式展现出来.本期Python培训教 ...

  2. Java异常之异常机制

    2019独角兽企业重金招聘Python工程师标准>>> Java异常处理机制依赖5个关键字try,catch,finally,throw,throws.try关键字后跟着可能出现异常 ...

  3. C# Note34: 异常机制相关小点

    1.使用throw和throw ex抛出异常的区别 通常,我们使用try/catch/finally语句块来捕获异常,那么在抛出异常的时候,使用throw和throw ex有什么区别呢? 假如,按顺序 ...

  4. java的异常机制面试题(转)

    java的异常机制面试题(转) 参考文章: (1)java的异常机制面试题(转) (2)https://www.cnblogs.com/ffaiss/p/11434639.html 备忘一下.

  5. Java异常机制及异常处理建议

    Java异常机制及异常处理建议 参考文章: (1)Java异常机制及异常处理建议 (2)https://www.cnblogs.com/wangxilei/p/9522259.html 备忘一下.

  6. C++ 异常机制分析

    C++ 异常机制分析 参考文章: (1)C++ 异常机制分析 (2)https://www.cnblogs.com/QG-whz/p/5136883.html 备忘一下.

  7. 全面理解java异常机制

    在理想状态下,程序会按照我们预想的步骤一步一步的执行,但是即使你是大牛,你也不可避免出错,所以java为我们提供了异常机制.本文将会从以下几个方面介绍java中的异常机制: 异常机制的层次结构 异常的 ...

  8. Java异常处理及异常机制介绍

    Java异常处理及异常机制介绍 当出现程序无法控制的外部环境问题(用户提供的文件不存在,文件内容损坏,网络不可用...)时,JAVA就会用异常对象来描述. JAVA中用2种方法处理异常: 1.在发生异 ...

  9. Java的知识点19——异常机制Exception

    异常(Exception)的概念 异常指程序运行过程中出现的非正常现象,例如用户输入错误.除数为零.需要处理的文件不存在.数组下标越界等. Java是采用面向对象的方式来处理异常的.处理过程: 1.  ...

最新文章

  1. 如何合并多个Django项目?
  2. Fluently NHibernate 插入CLOB字段
  3. tomcat启动命令行窗口出现乱码的解决方法
  4. Java Script 之 Promise
  5. keil5建立多文件的时候为什么总是出错
  6. 卡尔曼滤波器(Kalman Filter) 理解
  7. 牛客小白月赛18-记录
  8. 2021年合肥学院校程序设计竞赛 --H.简单的桌游问题
  9. 所经历的大文件数据导出(后台执行,自动生成)
  10. FastDFS安装脚本
  11. Java面试poi中excel版本大小_java 中 poi解析Excel文件版本问题解决办法
  12. 剑指 Offer II 024. 反转链表
  13. Javascript中call()和apply()的用法 ----1
  14. 移动互联网赌博的大礼包触发
  15. IE浏览器异常,无法正常使用,如何修复?
  16. React子组件给父组件传值
  17. html如何绘制树结构图,HTML 5 Canvas 递归画树
  18. 直下式LED背光源和侧入式LED背光源的区别以及哪个好呢
  19. RFID 有源,半源和无源的区别
  20. 未来软件开发的发展趋势

热门文章

  1. android 缩放透明动画,Android旋转、平移、缩放和透明度渐变的补间动画
  2. 有序链表转换二叉搜索树Python解法
  3. 列表子集Python解法
  4. 幼儿园带括号算式口诀_这么全的小学数学速算技巧、口诀不多见,教给孩子挺不错!...
  5. vue a-sub-menu 添加点击事件报错_Vue+TS 使用的问题(持续更)
  6. android queue用法,GitHub - rygz146/TQueue: Android 可以任意切换线程的任务队列, TQueue
  7. easyexcel 无模板写入_给位,问个问题,用easyExcel无模板导出数据时,怎么在指定单元格添加计算公式呢?...
  8. 数据库开发技术java方向_Java开发工程师(Web方向) - 03.数据库开发 - 第5章.MyBatis...
  9. 现在的python版本_现在python 流行哪个版本
  10. mysql 1005_MYSQL使用错误 MYSQL中ERROR 1005