前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >慢一点,你还想要与高性能代码背道而弛多久

慢一点,你还想要与高性能代码背道而弛多久

作者头像
烟雨平生
发布2023-03-07 16:37:59
1140
发布2023-03-07 16:37:59
举报
文章被收录于专栏:数字化之路数字化之路

软件工程领域的大师级人物 Robert C. Martin在《Clean Code》中讲道: 错误处理是十分必要的,但是如果对错误处理使用不当则会让代码变得十分臃肿,让阅读者看不清代码的逻辑,更严重的是,这也会让程序变得十分脆弱。

使用 Exception而不是返回码

返回码是一个历史遗留问题,在以前的没有 Exception的语言(比如c语言)中,它是有效且必要的,但是在有 Exception的语言中使用返回码是没有任何益处的。

对于使用返回码的函数,调用者在得到调用结果(这里是返回码)之后要立即去验证返回码,这对于代码的可读性和结构的合理性都是极大的挑战,使用「异常处理」能让业务逻辑和错误处理在代码结构上分离,代码的结构和逻辑会更清晰。

========华丽的分割线========

现在我们就来实测下这种抛异常的策略,是否会影响性能: 代码【源码已上传到github,地址在文末】:

代码语言:javascript
复制
/**
 * 相同条件下,同样的业务逻辑和IO下,比较抛异常和不抛异常场景下,
 * 在性能上有什么区别
 */
@Test
public void givenTwoScenario_whenOneHasExceptionAndAnotherNot_thenGetTheElapsedTime() {
    StopWatch stopWatch = new StopWatch("OneHasExceptionAndAnotherNot");
    stopWatch.start("hasNoException");
    int length = 1000000;
    for (int i = 0; i < length; i++) {
        doBizHasNoException(String.valueOf(i));
    }
    stopWatch.stop();

    stopWatch.start("hasException");
    for (int i = 0; i < length; i++) {
        doBizHasException(String.valueOf(i));
    }
    stopWatch.stop();
    log.info("{}", stopWatch.prettyPrint());
}

/**
 * 没有抛异常的场景【也打印个日志】
 *
 * @param i
 */
public void doBizHasNoException(String i) {
    try {
        log.info("result:{}", i);
    } catch (Exception e) {
        log.warn("{}", e.getMessage());
    }
}

/**
 * 抛异常的场景【打印个日志】
 *
 * @param i
 */
public void doBizHasException(String i) {
    try {
        throw new IllegalArgumentException(i);
    } catch (Exception e) {
        log.warn("{}", e.getMessage());
    }
}

实际执行效果:

代码语言:javascript
复制
10:19:26.327 [main] INFO com.tangcheng.learning.syntax.PerformanceAnalysisUseExceptionTest - StopWatch 'OneHasExceptionAndAnotherNot': running time (millis) = 17315
-----------------------------------------
ms     %     Task name
-----------------------------------------
05510  032%  hasNoException
11805  068%  hasException

可以看到,抛异常场景下,会更耗性能。 这个结论是不是很逆天,很不可思议。

当时也觉得百思不得其解,后来偶然在《极客时间》上听了 郑雨迪 讲的《深入拆解Java虚拟机》,感觉豁然开朗,那就不班门弄斧了,直接看看大佬来自jvm的视角:

代码语言:javascript
复制
异常实例的构造十分昂贵。
这是由于在构造异常实例时,Java虚拟机便需要生成该异常的栈轨迹(stack trace)。
该操作会逐一访问当前线程的Java栈帧,并且记录下各种调试信息,包括栈桢所指向方法的名字,方法所在的类名、文件名,以及在代码中的第几行触发该异常。

上面的文本不能copy,敲着比较费劲,那就直接截图了啊:

评论永远有经典:

测试用例源码路径: https://github.com/helloworldtang/spring-boot-cookbook/blob/v1.0.2-thymeleaf/learning-demo/src/test/java/com/tangcheng/learning/syntax/PerformanceAnalysisUseExceptionTest.java

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

本文分享自 的数字化之路 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用 Exception而不是返回码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档