【Java】java开发过程中一些优化的小细节

本文介绍了Java性能优化的多个方面,包括List优化,如根据ArrayList和LinkedList的特点选择合适的遍历方式;减少不必要的变量计算,避免重复调用list.size();利用移位操作提升计算效率;避免在循环内创建对象引用,减少内存消耗;以及使用equals方法对比常量避免空指针异常。此外,还提到了JVM参数调优,如-Xms和-Xmx的设置,以及内存管理和对象重用策略。最后,讨论了Map的高效遍历方式和字符串转换为字符串的优化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

List优化

对于不同类型的list,遍历时选择合适的迭代方式(最常用的ArrayList和LinkedList):
1)ArrayList实现了RandomAccess接口,使用普通for循环遍历性能比较好(实现RandomAccess接口表明其支持快速随机访问,jvm决定)
2)LinkedList没有实现RandomAccess接口,使用超级for循环(foreach)或者iterator迭代性能比较好

尽量减少对变量的重复计算:

明确一个概念,对方法的调用,即使方法中只有一句语句,也是有消耗的,包括创建栈帧、调用方法时保护现场、调用方法完毕时回复现场等。所以如下操作

For(int i = 0;i < list.size();i ++) {…}

建议替换为

For(int i = 0,size = list.size();i < size;i ++) {

}

这样,当list.size()很大的时候,就减少了很多的消耗

用移位代替乘除操作:

计算机层面运行的是机器可以识别的二进制码,所以性能层面的话,移位高于乘法,乘法性能高于除法(可以参考jdk源码)。例如Integer.java中有一段代码

r = i - ((q << 6) + (q << 5) + (q << 2));
等价于r = i - (q * 64 + q * 32 + q * 4)=i - (q * 100);
r = i - ((q << 3) + (q << 1));
等价于 r = i - (q * 8 + q * 2) = i - (q * 10);
*其中还有一段q = (i * 52429) >> (16 + 3)
明显是使用移位和乘法替代除法操作,因为2 <<(16 + 3) = 2 << 19 = 524288,所以(i * 52429)>>>(16+3) = i * 52429 / 524288 ≈ i * 0.1 = i / 10;

循环内不要不断创建对象引用:

例如

for(int i = 0; i < count; i ++) {
Object obj = new Object();
}

这种方式会导致内存中有count份Object对象引用存在,如果count很大的话,就很耗费内存了;
建议改为:

Object = null;
for(int i = 0;i < count;i ++){
obj = new Object();
}

这样内存中只存在一份Object对象引用,每次new的时候只想不同的Object

常量和变量使用equals比较,常量建议写在前边

例如:

a.String str = “123”;
if(str.equals(“123”)){…}

建议改为

if(“123”.equals(str)){…}

这样可以避免空指针(str = null时不会报NullPointerException)

@JVM 参数调优:
-Xms表示 JVM 初始化堆的大小,-Xmx表示 JVM 堆的最大值。这两个值的大小一般根据需要进行设 置。当应用程序需要的内存超出堆的最大值时虚拟机就会提示内存溢出,并且导致应用服务崩溃。因此一般建议堆的最大值设置为可用内存的最大值的 80%。
在 catalina.bat中,设置 JAVA_0PTS=‘-Xms256m- Xmx512m’,表示初始化内存为 256MB,
可以使用的最大内存为 512MB。

其他优化

将基本类型转为字符串,(类型).toString()最快,String.valueOf()次之, + “”最慢
使用有效率的方式遍历Map
便利map的方式很多,通常场景下需要遍历的是Map中的key和value,那么推荐使用的、效率最高的方式是:


Map<String,Object> map = new HashMap<>();
Map.put(111,222);
		Set<Map.Entry<String,Object>> entrySet = map.entrySet();
		Iterator<Map.Entry<String,Object>> iterator = entrySet.iterator();
		while (iterator.hasNext()) {
			Map.Entry<String,Object> entry = 					(Map.Entry<String,Object>)iterator.next();
		}

尽可能重用对象
特别是String对象的使用,出现字符串链接时应该使用StringBuilder/StringBuffer代替(如果是方法内局部变量拼接,建议使用StringBuilder,后者同步,性能差一些)。由于jvm不仅要花时间生成对象,以后可能还要花时间对这些对象进行垃圾回收和处理,因此,生成过多的对象将会给程序的性能带来很大的影响

如果能够预估到待添加内容的长度,为底层以数组方式实现的集合、工具类指定初始长度
比如ArrayList,LinkedList,StringBuilder,StringBuffer,HashMap,HashSet等
如果动态频繁添加数据,底层数组会发生频繁扩容,并且底层的扩容是新建数组,使用System.copy实现,替代旧数组,导致频繁的复制.

当复制大量数据时,使用System.arrayCopy()命令

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小冷coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值