让Java代码性能更高

本文探讨了Java中Map、List、Set等集合类的高效使用策略,包括Map的正确遍历方法、Collection的空检测优化、避免集合自我引用、初始化集合时指定大小、字符串拼接使用StringBuilder、List的随机访问技巧、以及频繁调用contains方法时使用Set的性能提升。

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

一.Map主键取值方法

当循环中只需要 Map 的主键时,迭代 keySet() 是正确的。但是,当需要主键和取值时,迭代 entrySet() 才是更高效的做法,比先迭代 keySet() 后再去 get 取值性能更佳。

创建Map
Map<String, String> map = new HashMap<String ,String>();
        for (int i = 0; i < 2000000; i++) {
            map.put("测试"+i ,"测试"+i);
        }
普遍的遍历方法 性能差
 for (String key : map.keySet()) {
            String value = map.get(key);
           // System.out.println(value);
        }
正确的遍历方法
for (Map.Entry<String, String> entry : map.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
        }
输出结果: 看出 entrySet() 才是更高效
二 .应该使用Collection.isEmpty()检测空

使用 Collection.size() 来检测空逻辑上没有问题,但是使用 Collection.isEmpty()使得代码更易读,并且可以获得更好的性能。
任何 Collection.isEmpty() 实现的时间复杂度都是 O(1) ,但是某些 Collection.size() 实现的时间复杂度可能是 O(n) 。

一般写法 不好
        if (collection.size() == 0) {
        }
优化后写法
        if (collection.isEmpty()) {
        }

如果需要还需要检测 null ,可采用CollectionUtils.isEmpty(collection)和CollectionUtils.isNotEmpty(collection)。

三. 不要把集合对象传给自己

此外,由于某些方法要求参数在执行期间保持不变,因此将集合传递给自身可能会导致异常行为。

List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
if (list.containsAll(list)) { // 无意义,总是返回true
}
list.removeAll(list); // 性能差, 直接使用clear()
三 集合初始化尽量指定大小

java 的集合类用起来十分方便,但是看源码可知,集合也是有大小限制的。
每次扩容的时间复杂度很有可能是 O(n) ,所以尽量指定可预知的集合大小,能减少集合的扩容次数。

反例:
int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>();
for (int i : arr) {
    list.add(i);
}
正例
int[] arr = new int[]{1, 2, 3};
List<Integer> list = new ArrayList<>(arr.length);
for (int i : arr) {
    list.add(i);

}

四 字符串拼接使用StringBuilder

一般的字符串拼接在编译期 java 会进行优化,但是在循环中字符串拼接, java 编译期无法做到优化,所以需要使用 StringBuilder 进行替换。

反例
String s = "";
for (int i = 0; i < 10; i++) {
    s += i;
}
正例
String a = "a";
String b = "b";
String c = "c";
String s = a + b + c; // 没问题,java编译器会进行优化
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
    sb.append(i);  // 循环中,java编译器无法进行优化,所以要手动使用StringBuilder
}
List的随机访问

大家都知道数组和链表的区别:数组的随机访问效率更高。当调用方法获取到 List 后,如果想随机访问其中的数据,并不知道该数组内部实现是链表还是数组,怎么办呢?
可以判断它是否实现RandomAccess接口。

// 调用别人的服务获取到list
List<Integer> list = otherService.getList();
if (list instanceof RandomAccess) {
    // 内部数组实现,可以随机访问
    System.out.println(list.get(list.size() - 1));
} else {
    // 内部可能是链表实现,随机访问效率低
}

频繁调用 Collection.contains 方法请使用 Set
在 java 集合类库中,List 的 contains 方法普遍时间复杂度是 O(n) ,
如果在代码中需要频繁调用 contains 方法查找数据,可以先将 list 转换成 HashSet 实现,将 O(n) 的时间复杂度降为 O(1) 。
反例:

ArrayList<Integer> list = otherService.getList();
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
    // 时间复杂度O(n)
    list.contains(i);
}

正例:

ArrayList<Integer> list = otherService.getList();
Set<Integer> set = new HashSet(list);
for (int i = 0; i <= Integer.MAX_VALUE; i++) {
    // 时间复杂度O(1)
    set.contains(i);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值