[转帖]19个小细节,让你提升Java代码的运行效率

细节,提升,java,代码,运行,效率 · 浏览次数 : 0

小编点评

**1.局部变量** - 通过局部变量可以避免在堆上分配由于堆资源是多线程共享的,是垃圾回收器工作的主要区域,过多的对象会造成 GC 压力。 - 避免使用 `+` 和 `StringBuilder` 等方法在字符串拼接中,可以使用 `StringBuilder` 或 `StringBuffer`。 **2. 削弱变量的作用范围** - 将变量移动到 if 语句内部可以减少对象的创建数量。 **3. 使用类名方式访问静态变量** - 当变量的作用范围在类中定义时,可以使用类名方式访问静态变量。 **4. 重写对象的HashCode** - 不要简单地返回固定值,开发时重写 `hashCode` 和 `equals` 方法时,要考虑性能的影响。 **5. 使用 StringBuilder 或 StringBuffer 进行字符串拼接** - 使用 `StringBuilder` 或 `StringBuffer` 进行字符串拼接可以减少 String 的创建数量。 **6. 优化 HashMap 初始化** - 在 HashMap 初始化的时候,尽量指定初始值大小。 **7. 遍历 Map 的方法** - 使用 EntrySet 方法可以直接返回 set 对象,省去再次获取集合中的元素。 **8. 使用 ThreadLocalRandom 类** - 在多线程环境下,可以使用 `ThreadLocalRandom` 类来优化 Random 的生成性能。 **9. 自增推荐使用 LongAddr 自增运算** - 通过 `synchronized` 和 `volatile` 的组合,或使用原子类(比如 `AtomicLong`)进行性能提升。 **10. 不要在多线程下使用同一个 RandomRandom 类的 seed** - 使用 `ThreadLocalRandom` 类可以解决这个问题。 **11. 不要在循环中使用 try catch 理念** - 异常处理的效率应该与代码逻辑无关。 **12. 避免捕捉 RuntimeException** - 使用 `try catch` 语句进行异常处理,避免使用 `catch` 语句。 **13. 使用 PreparedStatement 进行预编译** - 使用 `PreparedStatement` 进行预编译可以提高 SQL 的执行性能。 **14. 减少事务的作用范围** - 使用事务可以减少每次操作对数据库的锁竞争时间。 **15. 减少日志打印的频率** - 可以将日志打印的频率降低到最低级别。 **16. 使用位移操作替代乘除法** - 使用位移操作可以极大地提高性能。 **17. 不要打印大集合或使用大集合的 toString 方法** - 在集合中元素很多情况下,打印大集合会导致内存溢出。 **18. 使用位移操作替代乘除法** - 使用位移操作可以极大地提高性能。 **19. 正则表达式优化** - 使用预先编译的正则表达式可以提高速度。 **20. 使用 invoke 包下的 MethodHandle** - 在某些情况下,使用 `invoke` 包下的 `MethodHandle` 进行性能提升。

正文

https://cloud.tencent.com/developer/article/2168091?areaSource=104001.16&traceId=zcVNsKTUApF9rNJSkcCbB

 

1.使用局部变量可避免在堆上分配

由于堆资源是多线程共享的,是垃圾回收器工作的主要区域,过多的对象会造成 GC 压力。可以通过局部变量的方式,将变量在栈上分配。这种方式变量会随着方法执行的完毕而销毁,能够减轻 GC 的压力。

2.削弱变量的作用范围

注意变量的作用范围,尽量减少对象的创建。如下面的代码,变量 a 每次进入方法都会创建,可以将它移动到 if 语句内部。

3.使用类名方式访问静态变量

有的同学习惯使用对象访问静态变量,这种方式多了一步寻址操作,需要先找到变量对应的类,再找到类对应的变量。

4.字符串拼接不要使用 ”+”

字符串拼接,使用 StringBuilder或者StringBuffer,不要使用 + 号。

5.重写对象的HashCode,不要简单地返回固定值

开发时重写 HashCodeEquals 方法时,会把 HashCode的值返回固定的 0,而这样做是不恰当的。

当这些对象存入 HashMap 时,性能就会非常低,因为 HashMap是通过 HashCode 定位到 Hash 槽,有冲突的时候,才会使用链表或者红黑树组织节点。固定地返回 0,相当于把 Hash 寻址功能给废除了。

6.HashMap等集合初始化的时候,尽量指定初始值大小

通过指定初始值大小可减少扩容造成的性能损耗。

7.遍历Map 的时候,使用 EntrySet 方法

使用 EntrySet 方法,可以直接返回 set 对象,直接拿来用即可;而使用 KeySet 方法,获得的是key 的集合,需要再进行一次 get 操作,多了一个操作步骤。所以更推荐使用 EntrySet 方式遍历 Map。

8.不要在多线程下使用同一个 Random

Random 类的 seed 会在并发访问的情况下发生竞争,造成性能降低,建议在多线程环境下使用 ThreadLocalRandom 类。

在 Linux 上,通过加入 JVM 配置 -Djava.security.egd=file:/dev/./urandom,使用 urandom 随机生成器,在进行随机数获取时,速度会更快。

9.自增推荐使用 LongAddr

自增运算可以通过 synchronized 和 volatile 的组合,或者也可以使用原子类(比如 AtomicLong)。

后者的速度比前者要高一些,AtomicLong 使用 CAS 进行比较替换,在线程多的情况下会造成过多无效自旋,所以可以使用 LongAdder 替换 AtomicLong 进行进一步的性能提升。

10.不要使用异常控制程序流程

异常,是用来了解并解决程序中遇到的各种不正常的情况,它的实现方式比较昂贵,比平常的条件判断语句效率要低很多。

这是因为异常在字节码层面,需要生成一个如下所示的异常表(Exception table),多了很多判断步骤。

11.不要在循环中使用 try catch

道理与上面类似,很多文章介绍,不要把异常处理放在循环里,而应该把它放在最外层,但实际测试情况表明这两种方式性能相差并不大。

既然性能没什么差别,那么就推荐根据业务的需求进行编码。比如,循环遇到异常时,不允许中断,也就是允许在发生异常的时候能够继续运行下去,那么异常就只能在 for 循环里进行处理。

12.不要捕捉 RuntimeException

Java 异常分为两种,一种是可以通过预检查机制避免的 RuntimeException;另外一种就是普通异常。

其中,RuntimeException 不应该通过 catch 语句去捕捉,而应该使用编码手段进行规避。

13.合理使用 PreparedStatement

PreparedStatement 使用预编译对 SQL 的执行进行提速,大多数数据库都会努力对这些能够复用的查询语句进行预编译优化,并能够将这些编译结果缓存起来。

这样等到下次用到的时候,就可以很快进行执行,也就少了一步对 SQL 的解析动作。

PreparedStatement 还能提高程序的安全性,能够有效防止 SQL 注入。

但如果你的程序每次 SQL 都会变化,不得不手工拼接一些数据,那么 PreparedStatement 就失去了它的作用,反而使用普通的 Statement 速度会更快一些。

14.日志打印的注意事项

debug 输出一些调试信息,然后在线上关掉它。

15.减少事务的作用范围

如果的程序使用了事务,那一定要注意事务的作用范围,尽量以最快的速度完成事务操作。这是因为,事务的隔离性是使用锁实现的。

16.使用位移操作替代乘除法

计算机是使用二进制表示的,位移操作会极大地提高性能。

  • << 左移相当于乘以 2;
  • << 右移相当于除以 2;
  • >>>无符号右移相当于除以 2,但它会忽略符号位,空位都以 0 补齐。

17.不要打印大集合或者使用大集合的 toString 方法

有的开发喜欢将集合作为字符串输出到日志文件中,这个习惯是非常不好的。

拿 ArrayList 来说,它需要遍历所有的元素来迭代生成字符串。在集合中元素非常多的情况下,这不仅会占用大量的内存空间,执行效率也非常慢

18.尽量少在程序中使用反射

反射的功能很强大,但它是通过解析字节码实现的,性能就不是很理想。

现实中有很多对反射的优化方法,比如把反射执行的过程(比如 Method)缓存起来,使用复用来加快反射速度。

Java 7.0 之后,加入了新的包 java.lang.invoke,同时加入了新的 JVM 字节码指令 invokedynamic,用来支持从 JVM 层面,直接通过字符串对目标方法进行调用。

如果你对性能有非常苛刻的要求,则使用 invoke 包下的 MethodHandle 对代码进行着重优化,但它的编程不如反射方便,在平常的编码中,反射依然是首选。

19.正则表达式可以预先编译,加快速度

Java 的正则表达式需要先编译再使用。

与[转帖]19个小细节,让你提升Java代码的运行效率相似的内容:

[转帖]19个小细节,让你提升Java代码的运行效率

https://cloud.tencent.com/developer/article/2168091?areaSource=104001.16&traceId=zcVNsKTUApF9rNJSkcCbB 1.使用局部变量可避免在堆上分配 由于堆资源是多线程共享的,是垃圾回收器工作的主要区域,过多的

[转帖]19.awk报告生成器,文本解释器

在本博客中,AWK是一个系列文章,本人会尽量以通俗易懂的方式递进的总结awk命令的相关知识点。 awk系列博文直达链接:AWK命令总结之从放弃到入门 我们先来用专业的术语描述一下awk是什么,如果你看不懂,没关系,我们会再用”大白话”解释一遍。 awk是一个报告生成器,它拥有强大的文本格式化的能力,

[转帖]达梦数据库 DM8 中 注册服务 说明

2019-10-29 19:3830480原创DM 达梦 本文链接:https://www.cndba.cn/dave/article/3753 达梦数据库 DM8 中 注册服务 说明 在之前的博客我们了解了DM7中的服务注册,如下: DM7 达梦数据库 通过dminit 创建 并 注册 数据库实例

[转帖]LVS 20倍的负载不均衡,原来是内核的这个Bug

https://plantegg.github.io/2019/07/19/%E5%B0%B1%E6%98%AF%E8%A6%81%E4%BD%A0%E6%87%82%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1--%E8%B4%9F%E8%BD%BD%E5%9D%87%E

[转帖]MySQL 8.0.19 instant add column,亿级数据秒速增加字段

一、MySQL DDL 的方法 MySQL 在大型表上的 DDL 会带来耗时较久、负载较高、额外空间占用、MDL、主从同步延时等情况。需要特别引起重视,而MySQL 的 DDL 有很多种方法。 MySQL 本身自带三种方法,分别是:copy、inplace、instant。 copy 算法为最古老的

[转帖]kubernetes Flannel网络剖析

https://plantegg.github.io/2022/01/19/kubernetes_Flannel%E7%BD%91%E7%BB%9C%E5%89%96%E6%9E%90/ cni(Container Network Interface) CNI 全称为 Container Netwo

[转帖]kubernetes calico网络

https://plantegg.github.io/2022/01/19/kubernetes%20calico%E7%BD%91%E7%BB%9C/ cni 网络 cni0 is a Linux network bridge device, all veth devices will conne

[转帖]kubernetes calico网络

https://plantegg.github.io/2022/01/19/kubernetes%20calico%E7%BD%91%E7%BB%9C/ cni 网络 cni0 is a Linux network bridge device, all veth devices will conne

[转帖]精通awk系列(19):awk流程控制之break、continue、next、nextfile、exit语句

https://www.cnblogs.com/f-ck-need-u/ 回到: Linux系列文章 Shell系列文章 Awk系列文章 break和continue break可退出for、while、do...while、switch语句。 continue可让for、while、do...wh

[转帖]技术分享 | 国产麒麟 arm 上编译安装 xtrabackup8

原创 发布于 2022-07-19 13:29:29 3220 举报 作者:王向 爱可生 DBA 团队成员,负责公司 DMP 产品的运维和客户 MySQL 问题的处理。擅长数据库故障处理。对数据库技术和 python 有着浓厚的兴趣。 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随