java性能優(yōu)化技巧二
來源:程序員人生 發(fā)布時間:2015-04-15 08:59:48 閱讀次數(shù):2898次
之前整理過1篇java性能優(yōu)化的博客,鏈接java性能優(yōu)化1,今天補充幾個
1. 謹慎對待Java的循環(huán)遍歷
Java中的列表遍歷可比它看起來要麻煩多了。就以下面兩段代碼為例:
A:
從Java的這篇 文檔我們可以了解到: “1個HashMap 實例有兩個影響它性能的因素:初始大小和加載因子(load factor)。 當哈希表的大小到達初始大小和加載因子的乘積的時候,哈希表會進行 rehash操作。如果在1個HashMap 實例里面要存儲多個映照關(guān)系時,我們需要設(shè)置足夠大的初始化大小以便更有效地存儲映照關(guān)系而不是讓哈希表自動增長讓后rehash,造成性能瓶頸。”
常常碰到需要遍歷1個 ArrayList 并將這些元素保存到 HashMap 里面去,將這個 HashMap 初始化預(yù)期的大小可以免再次哈希所帶來的開消。初始化大小可以設(shè)置為輸入的數(shù)組大小除以默許加載因子的結(jié)果值(這里取0.7):
- 優(yōu)化前的代碼:
HashMap<String,Foo> _map;
void addObjects(List<Foo> input)
{
_map = new HashMap<String, Foo>();
for(Foo f: input)
{
_map.put(f.getId(), f);
}
}
優(yōu)化后的代碼HashMap<String,Foo> _map;
void addObjects(List<Foo> input)
{
_map = new HashMap<String, Foo>((int)Math.ceil(input.size() / 0.7));
for(Foo f: input)
{
_map.put(f.getId(), f);
}
}
3. 延遲表達式的計算
在Java中,所有的方法參數(shù)會在方法調(diào)用之前,只要有方法參數(shù)是1個表達式的都會先對這個表達式進行計算(從左到右)。這個規(guī)則會致使1些沒必要要的操作。斟酌到下面1個場景:使用ComparisonChain比較兩個 Foo 對象。使用這樣的比較鏈條的1個好處就是在比較的進程中只要1個 compareTo 方法返回了1個非零值全部比較就結(jié)束了,避免了許多無謂的比較。例如現(xiàn)在這個場景中的要比較的對象最早斟酌他們的score, 然后是 position, 最后就是 _bar 這個屬性了:
public class Foo {
private float _score;
private int _position;
private Bar _bar;
public int compareTo (Foo other) {
return ComparisonChain.start().
compare(_score, other.getScore()).
compare(_position, other.getPosition()).
compare(_bar.toString(), other.getBar().toString()).
result;
}
}
但是上面這類實現(xiàn)方式總是會先生成兩個 String 對象來保存 bar.toString() 和other.getBar().toString() 的值,即便這兩個字符串的比較可能不需要。避免這樣的開消,可以為Bar 對象實現(xiàn)1個 comparator:
public class Foo {
private float _score;
private int _position;
private Bar _bar;
private final BarComparator BAR_COMPARATOR = new BarComparator();
public int compareTo (Foo other) {
return ComparisonChain.start().
compare(_score, other.getScore()).
compare(_position, other.getPosition()).
compare(_bar, other.getBar(), BAR_COMPARATOR).
result();
}
private static class BarComparator implements Comparator<Bar> {
@Override
public int compare(Bar a, Bar b) {
return a.toString().compareTo(b.toString());
}
}
}
4. 提早編譯正則表達式
字符串的操作在Java中算是開消比較大的操作。還好Java提供了1些工具讓正則表達式盡量地高效。動態(tài)的正則表達式在實踐中比較少見。在接下來要舉的例子中,每次調(diào)用 String.replaceAll() 都包括了1個常量模式利用到輸入值中去。因此我們預(yù)先編譯這個模式可以節(jié)省CPU和內(nèi)存的開消。
優(yōu)化前:
private String transform(String term) {
return outputTerm = term.replaceAll(_regex, _replacement);
}
- 優(yōu)化后:
private final Pattern _pattern = Pattern.compile(_regex);
private String transform(String term) {
return outputTerm = _pattern.matcher(term).replaceAll(_replacement);
}
5. 盡量地緩存Cache it if you can
將結(jié)果保存在緩存里也是1個避免過量開消的方法。現(xiàn)在已有多種LRU(Least Recently Used )緩存算法實現(xiàn)。
6. String的intern方法有用,但是也有危險
String 的 intern 特性有時候可以代替緩存來使用。
從這篇文檔,我們可以知道:
“A pool of strings, initially empty, is maintained privately by the class String. When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned”.
這個特性跟緩存很類似,但有1個限制,你不能設(shè)置最多可容納的元素數(shù)目。因此,如果這些intern的字符串沒有限制(比如字符串代表著1些唯1的id),那末它會讓內(nèi)存占用飛速增長。
作者:jason0539
博客:http://blog.csdn.net/jason0539(轉(zhuǎn)載請說明出處)
掃碼關(guān)注我微信公眾號
生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈