Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Clean Code系列之异常处理

Clean Code系列之异常处理

作者头像
码农戏码
发布于 2022-11-18 01:43:59
发布于 2022-11-18 01:43:59
42400
代码可运行
举报
文章被收录于专栏:DDDDDD
运行总次数:0
代码可运行

先前已经对异常如何设计,如何实践异常都写了几篇阐述了。再一次从Clean Code角度来谈谈异常的使用。

1、使用异常替代返回错误码

为什么?是从函数的角度去考虑:

函数要么做什么事,要么回答什么事,但二者不可得兼。也就是修改某对象状态,或者是返回该对象的有关信息。也就是指令与询问分隔开来

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
boolean set(String attribute,String value);

该函数设置某个指定属性,如果成功,就返回true,如果不存在那个属性,就返回false。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(set("website","zhuxingsheng.com")){
    //
}

但从读者角度考虑一下,它是在问websit属性值是否之前已经设置为zhuxingsheng.com,还是在问websit属性值是否成功设置为zhuxingsheng.com呢?从该行语句很难判断其含义,因为set是动词还是形容词并不清楚。

作者本意是,set是一个动词,但在if语句的上下文中,感觉它是一个形容词。该语句读起来像是在说“如果websit属性值之前已经被设置为zhuxingsheng.com”,而不是“设置websit属性值为zhuxingsheng.com,看看是否可行,然后...”。

要解决这个问题,可以将set函数重命名为setAndCheckIfExists,但这对提高if语句的可读性帮助不大。真正的解决方案是把指令与询问分隔开来,防止产生混淆:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(attributeExists("website"){
    setAttribute("website","zhuxingsheng.com");
}

在《领域服务是抛出异常还是返回错误码》[1],提到过如何编写返回错误码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(deletePage(page)) == OK){

}

但这样,从指令式函数返回错误码,有些违反指令与询问分隔的规则。

虽然这儿没有像上面的示例一样,引起动词与形容词的混淆,却会导致更深层次嵌套结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(deletePage(page) == OK){
    if(deleteRefrence(page.name) == OK) {
        if (deleteKey(page.name.key()) == OK) {
            //
        } else {
          //  
        }
    } else {
        //
    }
} else {
    //
}

使用异常替代错误码,错误处理代码能从主路径代码中分离出来:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
try {
    deletePage(page);
    deleteRefrence(page.name);
    deleteKey(page.name.key());
} catch (Exception e) {

}

抽离try/catch 代码块

try/catch代码块丑陋不堪,搞乱了代码结构,把错误处理与正常流程结构分离开来。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void delete(Page page) {
    try {
        deltePageAndAllReferences(page)
    } catch(Exception e) {
        log;
    }
}

正常流程结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void deletePageAndAllReferences(Page page) {
    deletePage(page);
    deleteRefrence(page.name);
    deleteKey(page.name.key());
}

这样子代码干净了些,而且函数只干一件事。错误处理就是一件事。

想要更简化一下try/catch代码块,可以使用vavr工具包中的Try类

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 Try.of((page) -> deltePageAndAllReferences(page)).onFailure(e -> log(e));

写法详情可观看小视频

ErrorCode枚举类

返回的错误码,我们常会使用一个常量类或者枚举定义所有错误码。

当新增逻辑需要增加新错误码时,就会增加新代码,而且还要来修改这个错误码类。

这样的类被称为依赖磁铁,当这个类修改时,其他所有类都需要重新编译和部署。

使用异常类代替错误码,新异常可以从异常类派生出来,而无须重新编译或重新部署。

2、使用未检查异常

在之前的异常文章中,提到检查异常有很强的穿透力,当类调用链路长,在底层方法上增加新检查异常就会导致上层所有方法修改声明,有点违反OCP。

3、异常防腐

在DDD中有防腐层的概念,通过防腐层去隔离两个界限上下文的变化。

异常也有类似的情况。

当调用第三方API时,会需要处理异常情况。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ThirdPartAPI third = new ThirdPartAPI();

try {
    third.open();
} catch (Third1Exception e) {
    //
} catch (Thrid2Exception e) {
    //
} catch (Third3Exception e) {
    //
} finally {

}

首先我们需要打包这个第三方API,降低对它的依赖;也不必绑死在某一特定供应商API上,定义自己的API还要抽象异常

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ThirdPartService {
    public void open() {
        try {
            third.open();
        } catch (Third1Exception e) {
            //
            throw new SelfException(e);
        } catch (Thrid2Exception e) {
            //
            throw new SelfException(e);
        } catch (Third3Exception e) {
            //
            throw new SelfException(e);
        } finally {

        }
    }
}

上面代码,定义了抽象的ThirdPartSevice,并且抽象出SelfException。

总结

经过上面的三种手法,可以让代码在处理异常时,更加整洁。

References

[1] 《领域服务是抛出异常还是返回错误码》: https://www.zhuxingsheng.com/blog/does-the-domain-service-throw-an-exception-or-return-an-error-code.html

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农戏码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
代码整洁之道-读书笔记之函数
一函数理论上只做一件事情,只做一个抽象层次的事情,通俗的说就是看看当前函数是否还可以拆分出一个函数,如果可以说明就不是做一件事
特特
2022/09/30
4920
函数重构之道
以下代码做了好几件事情。它创建缓冲区、获取页面、搜索继承下来的页面、渲染路径、添加神秘的字符串、生产HTML等等。
栋先生
2018/09/29
4950
Python 工匠: 异常处理的三个好习惯
“ 如果你用 Python 编程,那么你就无法避开异常,因为异常在这门语言里无处不在。打个比方,当你在脚本执行时按 ctrl+c 退出,解释器就会产生一个 KeyboardInterrupt 异常。而 KeyError、 ValueError、 TypeError 等更是日常编程里随处可见的老朋友。 ” 前言 异常处理工作由“捕获”和“抛出”两部分组成。“捕获”指的是使用 try...except 包裹特定语句,妥当的完成错误流程处理。而恰当的使用 raise 主动“抛出”异常,更是优雅代码里必不可少的组
腾讯NEXT学位
2019/09/02
8530
Python 工匠: 异常处理的三个好习惯
Python 工匠:异常处理的三个好习惯
花下猫语: Python 工匠系列的文章很棒,它很好地将实战经验与理论融合起来,它的诚意体现在了写作风格、每个话题关注点与代码用例中。今天,继续给大家分享最新的作品(系列之六):
Python猫
2019/04/23
6670
Python 工匠: 异常处理的三个好习惯
如果你用 Python 编程,那么你就无法避开异常,因为异常在这门语言里无处不在。打个比方,当你在脚本执行时按 ctrl+c 退出,解释器就会产生一个 KeyboardInterrupt 异常。而 KeyError、 ValueError、 TypeError 等更是日常编程里随处可见的老朋友。
崔庆才
2019/07/16
9680
三个好习惯,帮你写好Python里的异常处理
如果你用 Python 编程,那么你就无法避开异常,因为异常在这门语言里无处不在。打个比方,当你在脚本执行时按 ctrl+c 退出,解释器就会产生一个 KeyboardInterrupt 异常。而 KeyError、 ValueError、 TypeError 等更是日常编程里随处可见的老朋友。
Python数据科学
2019/09/04
1.3K0
三个好习惯,帮你写好Python里的异常处理
【c++】c++异常&&c++的异常处理详解
实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的错误
用户10925563
2024/08/06
3450
【c++】c++异常&&c++的异常处理详解
WebFlux 全局异常处理实战
前后端分离开发,一般提供 REST API,正常返回会有响应体,异常情况下会有对应的错误码响应。
二哥聊运营工具
2021/12/17
2.6K0
WebFlux 全局异常处理实战
C++异常处理机制
实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的错误。
南桥
2024/09/20
1950
C++异常处理机制
Java中异常处理的9个最佳实践
在Java中进行处理异常并非是一件容易的事,初学者经常陷入困惑,甚至有经验的开发者也需要认真研讨哪些异常需要处理,哪些异常需要向上抛出。导致每个开发团队都会自己定制一套特有的异常处理规则,这使得新加入团队的成员都经历一段痛苦的适应期。
码农神说
2020/08/05
6940
Java中异常处理的9个最佳实践
Clean Code系列之DDD分层参数转换
从代码中,可以明显看出这是一段处理登陆请求的方法。在大多数项目中,这种代码很常见。
码农戏码
2022/04/15
9540
Clean Code系列之DDD分层参数转换
【C++航海王:追寻罗杰的编程之路】异常——错误处理方式之一
在C++编程中,异常处理是一种重要的技术,用于处理程序在运行时可能出现的错误或意外情况。异常是指在程序执行过程中发生的某种不正常的情况,例如除以零、内存访问错误或无效的输入等。传统的错误处理方式通常涉及使用错误代码或返回特殊值来指示问题,但这种方式可能会导致代码混乱、繁琐,并且容易被忽略或处理不当。
枫叶丹
2024/06/04
1620
【C++航海王:追寻罗杰的编程之路】异常——错误处理方式之一
改进异常处理的 6 条建议
来源:ImportNew - 唐尤华 , 合理地使用异常处理可以帮你节省数小时(甚至数天)调试时间。一个乘法异常会毁掉你的晚餐乃至周末计划。如果处置不及时,甚至对你的名誉都会造成影响。一个清晰的异常处理策略可以助你节省诊断、重现和问题纠正时间。下面是6条异常处理建议。 1. 使用一个系统全局异常类 不必为每种异常类型建立单独的类,一个就够了。确保这个异常类继承RuntimeException,这样可以减少类个数并且移除不必要的异常声明。 我知道你正在想什么:如果类型只有一个,那么怎么能知道异常具体是什么
企鹅号小编
2018/01/26
8660
C++异常处理深度探索:从基础概念到高级实践策略
在现代编程实践中,异常处理是一项至关重要的技能,特别是在开发复杂和大型系统时。C++作为一种强大而灵活的编程语言,提供了丰富的异常处理机制,使得开发者能够有效地管理运行时错误和异常情况。本文旨在深入探讨C++中的异常处理机制,从基本的语法结构到实际的应用场景,帮助读者掌握这一关键技能。 本文将从C++异常处理的基本概念出发,逐步介绍如何定义和抛出异常、如何捕获和处理异常,以及如何在复杂项目中有效运用异常处理机制。此外,我们还将讨论一些常见的异常处理策略和最佳实践,帮助读者避免常见陷阱,写出更加健壮和可靠的C++代码。
suye
2024/10/24
4320
【C++】异常
错误处理机制: 1.终止程序 如:assert 断言终止 ,会直接报告出现错误的位置 (assert只在debug版本生效)
lovevivi
2023/10/17
2970
【C++】异常
Java统一异常处理(配置文件集中化定义)
无论任何项目,都避免不了在运行期间出现的一些异常,并伴随着因业务逻辑的需要而给出相应的提示,使得系统变得更加友好,这类提示处理,我们统称为异常处理(exceptiona handling)。
xcbeyond
2020/04/01
1.4K0
Java统一异常处理(配置文件集中化定义)
Spring 中的统一异常处理
在具体的SSM项目开发中,由于Controller层为处于请求处理的最顶层,再往上就是框架代码的。 因此,肯定需要在Controller捕获所有异常,并且做适当处理,返回给前端一个友好的错误码。
芋道源码
2019/10/08
8350
【C++高阶】深入理解C++异常处理机制:从try到catch的全面解析
前言:在编程的浩瀚宇宙中,C++以其卓越的性能、强大的灵活性和对底层硬件的直接控制而著称,是无数开发者心中的瑰宝。然而,在追求高效与极致的路上,错误处理与异常管理往往成为不可忽视的重要环节。C++通过引入异常处理机制,为开发者提供了一套强大而灵活的工具,以优雅地应对程序执行过程中可能遇到的各种异常情况,从而确保程序的健壮性和可靠性
Eternity._
2024/08/09
1.3K0
【C++高阶】深入理解C++异常处理机制:从try到catch的全面解析
完善你的Laravel异常处理
异常处理是编程中十分重要但也最容易被人忽视的语言特性,它为开发者提供了处理程序运行时错误的机制,对于程序设计来说正确的异常处理能够防止泄露程序自身细节给用户,给开发者提供完整的错误回溯堆栈,同时也能提高程序的健壮性。
KevinYan
2019/10/13
3.1K0
十三、异常、类型转换和 lambda
C++ 中的异常处理是一种在程序执行期间处理错误或异常情况的机制。它允许程序在遇到错误时,不是立即崩溃或退出,而是以一种优雅的方式处理错误,可能是记录错误信息、释放资源或尝试恢复。
用户11332765
2024/10/28
3920
相关推荐
代码整洁之道-读书笔记之函数
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验