Java代码的一些优化思路
前两天看了一篇文章讲的是java代码的优化,本以为又要讲代码格式之类的,没想到讲的还挺有道理,接下来我就把其中重要的部分摘出来供大家参考。
列表的for循环
首先来看两段代码,看看他们的效率是不是一样的。
A:
private final List<Bar> _bars;
for(Bar bar : _bars) {
//Do important stuff
}
B:
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级别的,缓存少量的数据还是可以的。