提交 b106a3f1 编写于 作者: 沉默王二's avatar 沉默王二 💬

异常处理

上级 593d8281
......@@ -189,7 +189,7 @@
- [一文彻底搞懂Java异常处理,YYDS](docs/exception/gailan.md)
- [深入理解 Java 中的 try-with-resources](docs/exception/try-with-resouces.md)
- [Java异常处理的20个最佳实践](docs/exception/shijian.md)
- [Java空指针NullPointerException的传说](docs/exception/npe.md)
- [try-catch 捕获异常真的会影响性能吗?](docs/exception/npe.md)
## 常用工具类
......
......@@ -211,6 +211,7 @@ export const sidebarConfig = sidebar({
"try-with-resources",
"shijian",
"npe",
"try-catch-xingneng",
],
},
{
......
......@@ -12,6 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,npe,NullPointerException
---
# 8.4 空指针的传说
**空指针**,号称天下最强刺客。
......@@ -21,13 +22,13 @@ head:
... ...
我叫铁柱,我来到这个奇怪的世界已经一年了,我等了一年,穿越附赠的老爷爷、戒指、系统什么的我到现在都没发现。
我叫王二,我来到这个奇怪的世界已经一年了,我等了一年,穿越附赠的老爷爷、戒指、系统什么的我到现在都没发现。
而且这个世界看起来也太奇怪了,这里好像叫什么 **Java** 大陆,我只知道这个世界的最强者叫做 **Object**,听说是什么道祖级的存在,我也不知道是什么意思,毕竟我现在好像还是个菜鸡,别的主角一年都应该要飞升仙界了吧,我还连个小火球都放不出来。
哦,对了,上面的那段话是我在茶馆喝茶的时候听说书的先生说的,总觉得空指针这个名字怪怪的,好像在什么地方听说过。
我的头痛的毛病又犯了,我已经记不起来我为什么来到这里了,我只记得我的名字叫铁柱,其他的,我只感觉这个奇怪的世界有一种熟悉,但是我什么都记不起来了。
我的头痛的毛病又犯了,我已经记不起来我为什么来到这里了,我只记得我的名字叫王二,其他的,我只感觉这个奇怪的世界有一种熟悉,但是我什么都记不起来了。
算了,得过且过吧。
......@@ -223,7 +224,7 @@ Object听到这话,皱了皱眉,他沉默了一会儿,缓缓站起身子
可是,他为什么要给我,看他刚才的样子都想打我了,又突然给了我这些?还有他一直在说的规则之力又是什么?这座城市为什么又这么诡异?
>转载链接:[https://mp.weixin.qq.com/s/PDfd8HRtDZafXl47BCxyGg](https://mp.weixin.qq.com/s/PDfd8HRtDZafXl47BCxyGg)
>转载链接:[https://mp.weixin.qq.com/s/PDfd8HRtDZafXl47BCxyGg](https://mp.weixin.qq.com/s/PDfd8HRtDZafXl47BCxyGg),作者:艾小仙
----
......
---
title: 支付宝二面:使用 try-catch 捕获异常会影响性能吗?大部分人都会答错!
shortTitle: 支付宝二面:使用 try-catch 捕获异常会影响性能吗?大部分人都会答错!
description: 扯什么 try-catch 性能问题?
author: 是yes呀
title: try-catch 捕获异常真的会影响性能吗?
shortTitle: try-catch会影响性能吗?
category:
- 微信公众号
- Java核心
tag:
- 异常处理
description: Java程序员进阶之路,小白的零基础Java教程,从入门到进阶,try-catch会影响性能吗?
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,异常处理,java try-catch,java 异常性能
---
# 8.5 try-catch会影响性能吗?
“二哥,你看着这鬼代码,竟然在 for 循环里面搞了个 `try-catch`,不知道`try-catch`有性能损耗吗?” 老王煞有其事地指着屏幕里的代码:
```
```java
 for (int i = 0; i < 5000; i++) {
     try {
         dosth
......@@ -23,11 +30,9 @@ category:
“当然是把 `try-catch` 提到外面啊!” 老王脑子都不转一下,脱口而出。
“你是不是傻?且不说性能,这代码的目的明显是让循环内部单次调用出错不影响循环的运行,你其到外面业务逻辑不就变了吗!”
“你是不是傻?且不说性能,这代码的目的明显是让循环内部单次调用出错不影响循环的运行,你移到外面,业务逻辑不就变了吗!”
老王挠了挠他的地中海,“好像也是啊!”
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8V8dYibzJPUyLTOiaflK9O1oNu5ynX77ecE8GZBJMCu4FDOdZNMz66lJEw/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
老王挠了挠他的地中海,“好像也是啊!”
“回过头来,catch 整个 for 循环和在循环内部 catch,在不出错的情况下,其实性能差不多。” 我喝一口咖啡不经意地提到,准备在 老王前面秀一下。
......@@ -35,52 +40,84 @@ category:
果然, 老王上钩了,我二话不说直接打开 idea,一顿操作敲了以下代码:
```
public class TryCatchTest {
    @Benchmark
    public void tryfor(Blackhole blackhole) {
        try {
            for (int i = 0; i < 5000; i++) {
                blackhole.consume(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Benchmark
    public void fortry(Blackhole blackhole) {
        for (int i = 0; i < 5000; i++) {
            try {
                blackhole.consume(i);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
```java
public class TryCatchTest {
// 用 @Benchmark 注解标记一个方法作为基准测试方法
@Benchmark
public void tryfor(Blackhole blackhole) {
// 使用 try-catch 语句包装一个 for 循环
try {
for (int i = 0; i < 1000; i++) {
// 在循环中调用 Blackhole.consume() 方法
blackhole.consume(i);
}
} catch (Exception e) {
// 捕获异常并打印堆栈跟踪信息
e.printStackTrace();
}
}
// 用 @Benchmark 注解标记另一个方法作为基准测试方法
@Benchmark
public void fortry(Blackhole blackhole) {
// 使用 for 循环包装一个 try-catch 语句
for (int i = 0; i < 1000; i++) {
try {
// 在 try 块中调用 Blackhole.consume() 方法
blackhole.consume(i);
} catch (Exception e) {
// 捕获异常并打印堆栈跟踪信息
e.printStackTrace();
}
}
}
}
```
在这里,请允许我补充一些概念,以便大家能更好的理解这段代码。
>第一个:`@Benchmark` 是一个来自于 JMH(Java Microbenchmark Harness)库的注解,用来标记一个方法作为基准测试方法。JMH 是一个专门用于编写 [Java 微基准测试](https://hezhiqiang8909.gitbook.io/java/docs/javalib/jmh)的工具包,包含了一些用于测试 Java 代码性能和微调 JVM 的工具和库。使用 `@Benchmark` 注解标记的方法将被 JMH 自动识别为基准测试方法,并在运行时进行基准测试。在基准测试期间,JMH 会运行被标记的方法多次,并测量方法的执行时间、吞吐量、延迟等指标,并生成统计结果。
>第二个:在 JMH 进行基准测试时,为了避免 JIT 编译器优化掉测试代码中的某些操作,我们需要在测试代码中使用一些占位符,以便让编译器认为这些操作是有意义的,不应该被优化掉。`Blackhole.consume()` 方法就是这样的一个占位符。它用来占用一些 CPU 时间和内存空间,以确保测试结果的准确性和可靠性。
“BB 不如 show code,看到没, 老王,我把 `try-catch` 从 for 循环里面提出来跟在for循环里面做个对比跑一下,你猜猜两个差多少?”
“切,肯定 tryfor 性能好,想都不用想,不是的话我倒立洗头!” 老王信誓旦旦道。
我懒得跟他BB,直接开始了 benchmark,跑的结果如下:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VLO3DiaFJtQSOT2cxM9bGpxCcc2T3MYzNyibvEa9aAQA75s7BSkDCQUFA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
![](https://cdn.tobebetterjavaer.com/studymore/try-catch-xingneng-20230326204136.png)
可以看到,两者的性能(数字越大越好)其实差不多:
可以看到,两者的性能(数字越大越好)其实差不多:551063.024 VS 551525.861。
* fortry: 86,261(100359-14098) ~ 114,457(100359+14098)
* tryfor: 95,961(103216-7255) ~ 110,471(103216+7255)
在这里,简单普及一下 JMH 的使用指南。
我再调小(一般业务场景 for 循环次数都不会很多)下 for 循环的次数为 1000 ,结果也是差不多:
>第一步,在 pom.xml 文件中加入依赖。
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8Vu2NibLGzzsxxHx057xxdUleWkw0CzatjkicV5ATY8ibgZzg1OfwibnlERg/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
```
<!-- 引入 JMH 工具包 -->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.35</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.35</version>
</dependency>
```
>第二步,Intellij IDEA 中安装 JMH 插件。
![](https://cdn.tobebetterjavaer.com/studymore/try-catch-xingneng-20230326200811.png)
老王一看傻了:“说好的性能影响呢?怎么没了?”
>第三步,在代码编辑器中点击这个带有时间和运行的图标。然后静静等待结果就可以了,我本机(32G 内存 Intel i7 跑了 16 分钟,贼慢,因为 JMH 比较喜欢追求公平公正😂)
![](https://cdn.tobebetterjavaer.com/studymore/try-catch-xingneng-20230326200922.png)
老王一看傻了:“说好的性能影响呢?怎么没了?”
我直接一个javap,让 老王看看,其实两个实现在字节码层面没啥区别:
......@@ -88,13 +125,13 @@ public class TryCatchTest {
异常表记录的是 0 - 20 行,如果这些行里面的代码出现问题,直接跳到 23 行处理。
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VOqgDQpKC9d1bItvZvYDktfJZ1zHibBfxAQhMyg3TiaZAnHedevDpibfeA/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
![](https://cdn.tobebetterjavaer.com/studymore/try-catch-xingneng-20230326202911.png)
> fortry 的字节码
差别也就是异常表的范围小点,包的是 9-14 行,其它跟 tryfor 都差不多。
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VUF175V6eI88MdOGcJ5z2iagQiaVnkSU23y9qEgph35XbEicntzWdKFIFQ/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
![](https://cdn.tobebetterjavaer.com/studymore/try-catch-xingneng-20230326203005.png)
所以从字节码层面来看,没抛错两者的执行效率其实没啥差别。
......@@ -102,31 +139,58 @@ public class TryCatchTest {
这个说法确实有,在《Effective Java》这本书里就提到了 `try-catch` 性能问题:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8Vct7s8STia6NXdKtsm5PheGR97Pma1t08AbS5ibcJFWgm1dVSMBCO0Ubw/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
并且还有下面一段话:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VwWfNcOOtNgLnRP3MhRibuQgvLMf3Tpyq4BcRaoRGxvfJbAFOsLDglmQ/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
![](https://cdn.tobebetterjavaer.com/studymore/try-catch-xingneng-20230326203449.png)
正所谓听话不能听一半,以前读书时候最怕的就是一知半解,因为完全理解选择题能选对,完全不懂蒙可能蒙对,一知半解必定选到错误的选项!
《Effective Java》书中说的其实是不要用 `try-catch` 来代替正常的代码,书中的举例了正常的 for 循环肯定这样实现:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VrZdOBoCtfZXJOGMVHicy8u38sJnCLVsQoYjwUxIxfUO2ZaN4W7J1icicQ/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
```java
for ( Mountain m : range )
m.climb();
```
但有个卧龙偏偏不这样实现,要通过  `try-catch` 拐着弯来实现循环:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VeQ2RzfXhje63oVYzsTpIFS66ib9Y7NZYFHrrArnL9yTjBJgVATXNHmw/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
```java
/* Horrible abuse of exceptions. Don't ever do this! */
try {
int i = 0;
while ( true )
range[i++].climb();
} catch ( ArrayIndexOutOfBoundsException e ) {
}
```
这操作我只能说有点逆天,这两个实现的对比就有性能损耗了。
我们直接再跑下有`try-catch` 的代码和没 `try-catch`的 for 循环区别,代码如下:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VuQmWXtnqmlJme23R4gZEl8womzQdTaY7p8uADotSC5bS7ApTUhHDtg/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
```java
public class TryCatchTest1 {
@Benchmark
public void fornotry(Blackhole blackhole) {
for (int i = 0; i < 1000; i++) {
blackhole.consume(i);
}
}
@Benchmark
public void tryfor(Blackhole blackhole) {
for (int i = 0; i < 1000; i++) {
try {
blackhole.consume(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
```
结果如下:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VdLR0khht8pAnxOSVppCRUc8uQNNMY0qFBUYSU8vFpLnK05lR394Tgg/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
![](https://cdn.tobebetterjavaer.com/studymore/try-catch-xingneng-20230326210303.png)
+-差不多,直接看前面的分数对比,没有 `ry-catch` 的性能确实好些,这也和书中说的 `try-catch` 会影响 JVM 一些特定的优化说法吻合,但是具体没有说影响哪些优化,我猜测可能是指令重排之类的。
......@@ -142,33 +206,12 @@ public class TryCatchTest {
“洗洗洗,我们先喝个咖啡,晚上回去给你洗!”
晚上22点, 老王发来一张图片:
![](https://mmbiz.qpic.cn/mmbiz_png/eSdk75TK4nGlicp5nqtD0gsibIg8XCZk8VYrrLRlutAIJAJ2riaIVHud9fNwSlibJ2hGWd7ZEbZWN2gibbardhnRwBQ/640?wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1)
你别说,这头发至少比三毛多。
* * *
**微信8.0将好友放开到了一万,小伙伴可以加我大号了,先到先得,再满就真没了**
**扫描下方二维码即可加我微信啦,`2023,抱团取暖,一起牛逼。`**
![](https://mmbiz.qpic.cn/mmbiz_jpg/CKvMdchsUwkZFvnBvKpaEJNAIsxNEsXjdn86ZLzYmDxWWyLWKH20X6IRP2KR2mYiaVnoKqTIaPDeFPAfu92eegA/640?wx_fmt=jpeg)
## 推荐阅读
* [如何去除 List 中的重复元素?我一行代码搞定,赶紧拿去用!](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506448&idx=1&sn=ca9e42766d18f63a3f4612e8ee013882&scene=21#wechat_redirect)
* [IDEA 28 个天花板技巧,yyds!](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506429&idx=1&sn=5bd3be962978a8c25d1e490bb2e774cc&scene=21#wechat_redirect)
* [新来了个同事,代码命名规范是真优雅呀!代码如诗!!](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506219&idx=1&sn=8faa38c4906a9d898ee7ec4ecc7ad21a&scene=21#wechat_redirect)
* [订单超时自动取消的 3 种解决方案,yyds!](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506210&idx=1&sn=99ef122b136b88791a0c88aadd66f6c3&scene=21#wechat_redirect)
* [Spring Event + DDD = 王炸!!](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506199&idx=1&sn=457912818af109f0d6f9d707fb5bcd48&scene=21#wechat_redirect)
* [带了一个 3 年的开发,不会循环删除 List 中的元素,心态崩了。。。](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506173&idx=1&sn=cafc7f5d5da032bc29dce718fd427436&scene=21#wechat_redirect)
* [重磅更新!Mall实战教程全面升级,瞬间高大上了!](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247499376&idx=1&sn=3ed28795cdd35fbaa3506e74a56703b0&scene=21#wechat_redirect)
* [40K+Star!Mall电商实战项目开源回忆录!](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247486684&idx=1&sn=807fd808adac8019eb2095ba088efe54&scene=21#wechat_redirect)
>转载链接:[https://mp.weixin.qq.com/s/H870jLz32oEI_HCMVt1m5Q](https://mp.weixin.qq.com/s/H870jLz32oEI_HCMVt1m5Q),出处:沉默王二,作者:yes,修订和优化:沉默王二
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
![](https://mmbiz.qpic.cn/mmbiz_gif/CKvMdchsUwlkU1ysoMgG69dVYbCQcI6Byneb8ibzZWPfUCr3T8CuBicCSGyFE6SpAtxpxtDCp6VlZ4F1hEL1BNyg/640?wx_fmt=gif)
微信搜 **沉默王二** 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 **111** 即可免费领取。
>参考链接:[https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506471&idx=1&sn=68dbbb83ea983bd5499074bef9ff7712&chksm=fc2c662fcb5bef397209de9d3f045456d2a01d1da17e856d81a167b8ab940b4ebce3d9571e95&scene=126&sessionid=0#rd](https://mp.weixin.qq.com/s?__biz=MzU1Nzg4NjgyMw==&mid=2247506471&idx=1&sn=68dbbb83ea983bd5499074bef9ff7712&chksm=fc2c662fcb5bef397209de9d3f045456d2a01d1da17e856d81a167b8ab940b4ebce3d9571e95&scene=126&sessionid=0#rd),出处:macrozheng,整理:沉默王二
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/gongzhonghao.png)
\ No newline at end of file
......@@ -200,7 +200,9 @@ head:
- [一文彻底搞懂Java异常处理,YYDS](exception/gailan.md)
- [深入理解 Java 中的 try-with-resources](exception/try-with-resources.md)
- [Java异常处理的20个最佳实践](exception/shijian.md)
- [Java空指针NullPointerException的传说](exception/npe.md)
- [空指针NullPointerException的传说](exception/npe.md)
- [空指针NullPointerException的传说](exception/try-catch-xingneng.md)
- [try-catch 捕获异常真的会影响性能吗?](exception/npe.md)
### 常用工具类
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册