Java代码的一些优化思路

前两天看了一篇文章讲的是java代码的优化,本以为又要讲代码格式之类的,没想到讲的还挺有道理,接下来我就把其中重要的部分摘出来供大家参考。

列表的for循环

首先来看两段代码,看看他们的效率是不是一样的。

A:

1
2
3
4
5
6
7
private final List<Bar> _bars;

for(Bar bar : _bars) {

//Do important stuff

}

B:

1
2
3
4
5
6
7
8
9
private final List<Bar> _bars;

for(int i = 0; i < _bars.size(); i++) {

Bar bar = _bars.get(i);

//Do important stuff

}

初一看,第一段代码利用了java的一个语法糖,最终会变成迭代器来使用,他的时间复杂度是O(1)。第二段代码好像也是O(1),但是如果这个列表的实际实现类是LinkedList,那么他会变成O(n)。

集合的初始化大小

用了这么久java,大家肯定都知道集合的内部实现,例如ArrayList初始大小是10扩容大小是1.5倍,HashMap初始大小是16加载因子是0.75扩容大小是2倍等等。

但是,你有没有想过在new一个集合时指定他的初始大小呢?好像没有吧,很多人都是使用google的guava中Lists.newArrayList()方法直接创建集合。如果说在一个方法中使用集合时,你提前知道要存储的大小,那么就能避免在使用中动态扩容了。

延迟非必要计算

在你调用一个方法时,要填入入参,当入参是计算表达式时,在调用方法前,会先把计算表达式转变为最终的参数,例如methodA(a+b,a/c,a-d),他首先会计算出这三个数据,然后再调用方法。

其中可能出现的问题是什么?例如,在methodA方法中,当第一个参数等于某个值时,不需要用到第二个和第三个参数,那你后边的计算是不是可以避免?

提前生成耗时变量

字符串的一些操作在java中算是开销比较大的操作。例如String.replaceAll(regex,replacement)方法,如果第一个参数是String,则每次都要编译为正则表达式模式。如果该regex是固定的,那么可以提前编译好正则表达式模式。例如

private Pattern pattern = Pattern.compile(regex);

又例如DateFormat中的日期格式化,也可以提前编译好。

尽可能地缓存常用数据

如果你的程序中有有限的数据集合,并且经常使用,那么我建议你把它缓存起来,而不是一直从数据库中取得。例如你有一批总大小在几十mb级别的字符串经常使用,那么把这些字符串缓存在内存中还是有必要的。因为现在服务器的内存最少也是GB级别的,缓存少量的数据还是可以的。