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. 用 perfcollect 洞察 Linux 上.NET程序 CPU爆高

    一:背景 1. 讲故事 如果要分析 Linux上的 .NET程序 CPU 爆高,按以往的个性我肯定是抓个 dump 下来做事后分析,这种分析模式虽然不重但也不轻,还需要一定的底层知识,那有没有傻瓜式的 ...

  2. JVM运行时数据区之堆空间

    JVM运行时数据区之堆空间 1.核心概述 一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域.堆区在JVM 启动的时候即被创建,其空间大小也就确定了,是JVM管理的最大一块内存空间. & ...

  3. Mysql高级1-存储引擎

    一.Mysql体系结构 1.1.连接层 最上层是一个客户端和链接服务,主要完成一些类似于链接处理,授权认证,及相关的安全方案,服务器也会为安全接入的而每个客户端验证它所具有的操作权限 1.2.服务层 ...

  4. html表格基本标签

    1.<table>表签 <table>...</table>标签用于在html文档中后创建表格.它包含表名和表格本身内容的代码. 2.<tr>标签 &l ...

  5. JVM常用运行时参数说明

    前言 仅列出常用JVM调优参数,更多请转文末的官方文档链接. 堆内存 -Xmx,设置最大堆内存,默认为物理内存的1/4.示例:-Xmx4096m,设置为4G -Xms,设置初始内存,默认为物理内存的1 ...

  6. .NET5从零基础到精通:全面掌握.NET5开发技能

    C#版本新语法-官网: C#7:https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-7 C#8:https://docs.m ...

  7. Json 基于类 Newtonsoft.Json.Linq.JToken 的应用简介【C# 基础】

    〇.前言 在日常开发中,对于 Json 的使用还是比较频繁的,特别是 Json 对象和字符串或者实体对象之间的转换. 虽然几乎天天用,但是总是感觉没那么明了,今天结合微软的 Newtonsoft.Js ...

  8. Java - ReentrantLock锁分析

    Java - JUC核心类AbstractQueuedSynchronizer(AQS)底层实现 一.  AQS内部结构介绍 JUC是Java中一个包   java.util.concurrent . ...

  9. (2023.7.24)软件加密与解密-2-1-程序分析方法[XDbg].md

    body { font-size: 15px; color: rgba(51, 51, 51, 1); background: rgba(255, 255, 255, 1); font-family: ...

  10. 超全技术学习资料PDF分享

    技术学习资料分享,目前共20G,持续更新... Java学习资料: 大数据Hadoop: 这里不一一截图了,资源持续更新中. 关注下面公众号进行下载.