当前位置:首页 > 每日看点 > 正文内容

如何优雅的处理异常(java)?

卡卷网10个月前 (01-19)每日看点225

如何优雅的处理异常(java)?  第1张

大家好,我是半夏之沫 一名金融科技领域的JAVA系统研发
我希望将自己工作和学习中的经验以最朴实最严谨的方式分享给大家,共同进步
写作不易,期待大家的关注和点赞
关注微信公众号【技术探界

前言

一朋友问我Try-Catch写多了会不会让程序变慢,我不加思索的回答肯定不会,毕竟曾经研究过Java异常相关的字节码指令,只要被Try-Catch的代码不抛出异常,那么代码执行链路是不会加深的。

可事后我反复思考这个看似简单实则也不复杂的问题,我觉得顺着这个问题往下,还有一些东西可以思考,如果你感兴趣,那就跟随本文的视角一起来看下吧。

正文

首先郑重声明,单纯的针对一段代码添加Try-Catch,是 不会 影响性能的,我们可以通过下面的示例代码并结合字节码指令来看下。

示例代码如下所示。

public class TryCatchPerformance { public Response execute(String state) { return innerHandle(state); } public Response innerHandle(String state) { // todo 暂无逻辑 return null; } public static class Response { private int state; public Response(int state) { this.state = state; } public int getState() { return state; } public void setState(int state) { this.state = state; } } }

我们依次执行如下语句为上述代码生成字节码指令

# 编译Java文件 javac .\TryCatchPerformance.java # 反汇编字节码文件 javap -c .\TryCatchPerformance.class

可以得到execute() 方法的字节码指令如下。

public com.lee.learn.exception.TryCatchPerformance$Response execute(java.lang.String); Code: 0: aload_0 1: aload_1 2: invokevirtual #2 // Method innerHandle:(Ljava/lang/String;)Lcom/lee/learn/exception/TryCatchPerformance$Response; 5: areturn

现在对execute() 方法添加Try-Catch,如下所示。

public class TryCatchPerformance { public Response execute(String state) { try { return innerHandle(state); } catch (Exception e) { return new Response(500); } } public Response innerHandle(String state) { // todo 暂无逻辑 return null; } public static class Response { private int state; public Response(int state) { this.state = state; } public int getState() { return state; } public void setState(int state) { this.state = state; } } }

查看execute() 方法的字节码指令如下所示。

public com.lee.learn.exception.TryCatchPerformance$Response execute(java.lang.String); Code: 0: aload_0 1: aload_1 2: invokevirtual #2 // Method innerHandle:(Ljava/lang/String;)Lcom/lee/learn/exception/TryCatchPerformance$Response; 5: areturn 6: astore_2 7: new #4 // class com/lee/learn/exception/TryCatchPerformance$Response 10: dup 11: sipush 500 14: invokespecial #5 // Method com/lee/learn/exception/TryCatchPerformance$Response."<init>":(I)V 17: areturn Exception table: from to target type 0 5 6 Class java/lang/Exception

虽然添加Try-Catch后,字节码指令增加了很多条,但是通过Exception table异常表)我们可知,只有指令05在执行过程中抛出了Exception,才会跳转到指令6开始执行,换言之只要不抛出异常,那么在执行完指令5后方法就结束了,此时和没添加Try-Catch时的代码执行链路是一样的,也就是不抛出异常时,Try-Catch不会影响程序性能。

我们添加Try-Catch,其实就是为了做异常处理,也就是我们天然的认为被Try-Catch的代码就是会抛出异常的,而异常一旦发生,此时程序性能就会受到一定程度的影响,表现在如下两个方面。

  1. 异常对象创建有性能开销。具体表现在异常对象创建时会去爬栈得到方法调用链路信息
  2. Try-Catch捕获到异常后会让代码执行链路变深。

由此可见Try-Catch其实不会影响程序性能,但是异常的出现的的确确会影响,无论是JVM创建的异常,还是我们在代码中new出来的异常,都是会影响性能的。

所以现在我们来看看如下代码有什么可以优化的地方。

public class TryCatchPerformance { public Response execute(String state) { try { return innerHandle(state); } catch (Exception e) { return new Response(500); } } public Response innerHandle(String state) { if (state == null || state.isEmpty()) { // 通过异常中断执行 throw new IllegalStateException(); } else if ("success".equals(state)) { return new Response(200); } else { return new Response(400); } } public static class Response { private int state; public Response(int state) { this.state = state; } public int getState() { return state; } public void setState(int state) { this.state = state; } } }

上述代码的问题出现在innerHandle() ,仗着调用方有Try-Catch做异常处理,就在入参非法时通过创建异常来中断执行,我相信在实际的工程开发中,很多时候大家都是这么干的,因为有统一异常处理,那么通过抛出异常来中断执行并在统一异常处理的地方返回响应,是一件再平常不过的事情了,但是通过前面的分析我们知道,创建异常有性能开销,捕获异常并处理也有性能开销,这些性能开销其实是可以避免的,例如下面这样。

public class TryCatchPerformance { public Response execute(String state) { try { return innerHandle(state); } catch (Exception e) { return new Response(500); } } public Response innerHandle(String state) { if (state == null || state.isEmpty()) { // 通过提前返回响应的方式中断执行 return new Response(500); } else if ("success".equals(state)) { return new Response(200); } else { return new Response(400); } } public static class Response { private int state; public Response(int state) { this.state = state; } public int getState() { return state; } public void setState(int state) { this.state = state; } } }

如果当某个分支执行到了,我们也确切的知道该分支下的响应是什么,此时直接返回响应,相较于抛出异常后在统一异常处理那里返回响应,性能会更好。

总结

Try-Catch其实不会影响程序性能,因为在没有异常发生时,代码执行链路不会加深。

但是如果出现异常,那么程序性能就会受到影响,表现在如下两个方面。

  1. 异常对象创建有性能开销。具体表现在异常对象创建时会去爬栈得到方法调用链路信息
  2. Try-Catch捕获到异常后会让代码执行链路变深。

因此在日常开发中,可以适当增加防御性编程来防止JVM抛出异常,也建议尽量将主动的异常抛出替换为提前返回响应,总之就是尽量减少非必要的异常出现。


大家好,我是半夏之沫 一名金融科技领域的JAVA系统研发
我希望将自己工作和学习中的经验以最朴实最严谨的方式分享给大家,共同进步
写作不易,期待大家的关注和点赞
关注微信公众号【技术探界

如何优雅的处理异常(java)?  第2张

扫描二维码推送至手机访问。

版权声明:本文由卡卷网发布,如需转载请注明出处。

本文链接:https://www.kajuan.net/ttnews/2025/01/10145.html

分享给朋友:

相关文章

你捡过最大的漏是什么?

你捡过最大的漏是什么?

买了套二手房,软磨硬泡便宜了1个w 结果就是一屋子狼藉 原业主说反正你们要重新装修 就不收拾了 等完了你们一起收拾掉吧 落了很多柜子 电器是啥的 今天打开卧室柜子一看…现在是去存钱的路上有朋友知道这样存钱银行会给发大米跟油吗...

为什么有人觉得华为mate60只值2000?

为什么有人觉得华为mate60只值2000?

你以为买Mate60的人真的傻?真的那么爱国?国庆前,我家那傻子加价800多买了一台Mate60,当时还被我骂他是傻子。可是他说一回到公司就被老板同事朋友看到,拿去反复查看,都在惊叹他这么快就买到新机。跟亲戚朋友聚会,别人一看就知道他买的是...

为什么这次 Mac mini 的 M4 版本价格这么低?

为什么这次 Mac mini 的 M4 版本价格这么低?

扫了一眼这里的回答,目测没几个人真买过 Macbook、Mac mini且真正当主力工作机用过。这个初始(丐版)版本的机器实际谈不上多便宜,备受热捧有几个原因。它这代产品整体做了重新设计,大幅缩减了尺寸,真正称得上 Mini 了。对比前代,...

有没有能够兼顾便携并且流畅运行各种AI应用的笔记本?求推荐?

有没有能够兼顾便携并且流畅运行各种AI应用的笔记本?求推荐?

看了下题主的描述,可以考虑「联想YOGA Air 15 Aura AI元启版」,今年9月底出的一款轻薄本,也通过了英特尔Evo严苛认证。处理器用了英特尔最新的「酷睿 Ultra 7 258V」,主要亮点就是AI性能、图形处理能力和能效,很适...

有哪些让你目瞪口呆的 Bug ?

有哪些让你目瞪口呆的 Bug ?

成都有个监狱情况比较特殊,关押的基本全是重犯,而且还都是经济犯和政治犯,他们以前都是一方大佬,在自己的一亩三分地翻手为云覆手为雨,无非是不小心中箭落马或帮老大顶锅才进监狱,所以即使进来了,他们依然保持着体面和骄傲,依从性差,虽然不至于和监狱...

什么时候你意识到做技术永无出路?

什么时候你意识到做技术永无出路?

2016年,帮一个朋友的忙,写了个软件给他的工作室用, 象征性的收了5000块钱。大概过了三四年吧,他酒后吐真言,这个软件在他这个细分行业,很有用,他这几年把我写的这个软件卖了很多份出去,收益远超30万。因为是离线软件,给他的就是一个exe...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。