如果汉语背后没有文化,文化背后没有思想,思想背后没有精神,光TMD编造老娘和乔布斯没有说过的话,那中国永远不会是一个伟大的国家。——撒切尔夫人

《代码整洁之道》读书笔记四

错误处理

抽离Try/Catch代码块

函数应该只做一件事,错误处理就是一件事。

// bad
public void delete(Page page) {
    try{
        deletePage(page);
        registery.deleteReference(page.name);
        configKeys.deleteKey(page.name.makeKey();
    }catch(Expection e){
        logError(e);
    }
}

// good
public void delete(Page page) {
    try{
        // 将上例的操作,封装到一个方法
        deletePageAndAllReferences(page);
    }catch(Expection e){
        logError(e);
    }
}

使用非受控异常

受控异常:Checked Exception(FileException、SQLException等),这类异常必须写 try/catch,或者 throw抛出,否则编译通不过。

非受控异常:Unchecked Exception,这类异常也叫做运行时异常(与非受控异常 字数相等),这类异常不需要 try/catch,也不需要 throw抛出。即使 throw 了,上层调用函数也非必须捕获,编译能通过。

受控异常的代价就是违反开放/闭合原则。如果你在方法中抛出受控异常,这意味着每个调用该函数的函数都要修改,捕获新异常,或在其签名中添加合适的throw语句。对于一般的应用开发,受控异常依赖成本要高于收益成本,尽量 try/catch 处理,不要抛出。

给出异常发生的环境说明

应创建信息充分的错误信息,并和异常一起传递出去。在消息中,包括失败的操作和失败类型。如果你的应用程序有日志系统,传递足够的信息给catch块,并记录下来。

依调用者需要定义异常类

// bad
ACMEPort port = new ACMEPort(12);
try {
    port.open();
} catch(DeviceResponseException e) {
    reportPortError(e);
    logger.log("Device response exception",e);
} catch(ATM1212UnlockedException e) {
    reportPortError(e);
    logger.log("Unlock exception",e);
} catch(GMXError e) {
    reportPortError(e);
    logger.log("Device response exception",e);
} finally {
    // .....
}

通过打包调用API,确保它返回通过用异常类型,从而简化代码

// good
LocalPort port = new LocalPort(12);
try {
    port.open();
} catch(PortDeviceFailure e) {
    reportError(e);
    logger.log(e.getMessage(),e);
} finally {
    // .....
}

public class LocalPort{
 private ACMEPort innerPort;
 
 public LocalPort(int portNumber){
     innerPort = new ACMEPort(portNumber);
 }
 
 public open() {
  try {
       innerPort.open();
   } catch(DeviceResponseException e) {
           // 自定义的异常类
       throw new PortDeviceFailure(e);
   } catch(ATM1212UnlockedException e) {
       throw new PortDeviceFailure(e);
   } catch(GMXError e) {
       throw new PortDeviceFailure(e);
   }
 }
}

将第三方API打包是个良好的实践手段。当你打包一个第三方API,你就降低了对它的依赖。

其他

  • try catch语句块的范围不要太大,这样不利于对异常的分析
  • 别返回null值,这样可以减少调用者的防御性检测。与其返回null,不如抛出异常,或是返回特例对象(特例对象详见 p101)
  • 别传递null值,传递null就要求被调用函数需要一系列防御性检测,也就意味着程序有更大可能出错

posted @   崤函隳  阅读(75)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2020-11-08 2020/11/08 刘一辰的JAVA随笔
点击右上角即可分享
微信分享提示