|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
他们对jsp,servlet,javabean进行封装就是为了展示他们的某个思想,与java的开发并没有必然的关系,也不见得在所以情况下,别人使用起来会简单。比来在刷各至公司的手艺博客的时分,我在Linkedin的手艺博客下面发明了一篇很不错博文。这篇博文先容了Linkedin信息流两头层FeedMixer,它为Linkedin的Web主页,年夜学主页,公司主页和客户端等多个分发渠道供应支持(以下图所示)。
在FeedMixer内里用到了一个叫做SPR(念“super”)的库。博文讲的就是怎样优化SPR的java代码。上面就是他们总结的优化履历。
1.审慎看待Java的轮回遍历
Java中的列表遍历可比它看起来要贫苦多了。就以上面两段代码为例:
- A:
1
2
3
4
privatefinalList<Bar>_bars;
for(Barbar:_bars){
//Doimportantstuff
}
- B:
1
2
3
4
5
privatefinalList<Bar>_bars;
for(inti=0;i<_bars.size();i++){
Barbar=_bars.get(i);
//Doimportantstuff
}
代码A实行的时分会为这个笼统列表创立一个迭代器,而代码B就间接利用get(i)来猎取元素,相对代码A省往了迭代器的开支。
实践上这里仍是必要一些衡量的。代码A利用了迭代器,包管了在猎取元素的时分的工夫庞大度是O(1)(利用了getNext()和hasNext()办法),终极的工夫庞大度为O(n)。可是关于代码B,轮回里每次在挪用_bars.get(i)的时分消费的工夫庞大度为O(n)(假定这个list为一个LinkedList),那末终极代码B全部轮回的工夫庞大度就是O(n^2)(但假如代码B内里的list是ArrayList,那get(i)办法的工夫庞大度就是O(1)了)。以是在决意利用哪种遍历的体例的时分,我们必要思索列表的底层完成,列表的均匀长度和所利用的内存。最初由于我们必要优化内存,再加上ArrayList在年夜多半情形下查找的工夫庞大度为O(1),最初决意选择代码B所利用的办法。
2.在初始化的时分预估汇合的巨细
从Java的这篇文档我们能够懂得到:“一个HashMap实例有两个影响它功能的要素:初始巨细和加载因子(loadfactor)。[…]当哈希表的巨细到达初始巨细和加载因子的乘积的时分,哈希表会举行rehash操纵[…]假如在一个HashMap实例内里要存储多个映照干系时,我们必要设置充足年夜的初始化巨细以便更无效地存储映照干系而不是让哈希表主动增加让后rehash,形成功能瓶颈。”
在Linkedin理论的时分,经常碰着必要遍历一个ArrayList并将这些元素保留到HashMap内里往。将这个HashMap初始化预期的巨细能够制止再次哈希所带来的开支。初始化巨细能够设置为输出的数组巨细除以默许加载因子的了局值(这里取0.7):
- 优化前的代码:
1
2
3
4
5
6
7
8
9
HashMap<String,Foo>_map;
voidaddObjects(List<Foo>input)
{
_map=newHashMap<String,Foo>();
for(Foof:input)
{
_map.put(f.getId(),f);
}
}
- 优化后的代码
1
2
3
4
5
6
7
8
9
HashMap<String,Foo>_map;
voidaddObjects(List<Foo>input)
{
_map=newHashMap<String,Foo>((int)Math.ceil(input.size()/0.7));
for(Foof:input)
{
_map.put(f.getId(),f);
}
}
3.提早表达式的盘算
在Java中,一切的办法参数会在办法挪用之前,只需无方法参数是一个表达式的城市先这个表达式举行盘算(从左到右)。这个划定规矩会招致一些不用要的操纵。思索到上面一个场景:利用ComparisonChain对照两个Foo对象。利用如许的对照链条的一个优点就是在对照的过程当中只需一个compareTo办法前往了一个非零值全部对照就停止了,制止了很多无谓的对照。比方如今这个场景中的要对照的对象开始思索他们的score,然后是position,最初就是_bar这个属性了:
1
2
3
4
5
6
7
8
9
10
11
12
13
publicclassFoo{
privatefloat_score;
privateint_position;
privateBar_bar;
publicintcompareTo(Fooother){
returnComparisonChain.start().
compare(_score,other.getScore()).
compare(_position,other.getPosition()).
compare(_bar.toString(),other.getBar().toString()).
result;
}
}
可是下面这类完成体例老是会师长教师成两个String对象来保留bar.toString()和other.getBar().toString()的值,即便这两个字符串的对照大概不必要。制止如许的开支,能够为Bar对象完成一个comparator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
publicclassFoo{
privatefloat_score;
privateint_position;
privateBar_bar;
privatefinalBarComparatorBAR_COMPARATOR=newBarComparator();
publicintcompareTo(Fooother){
returnComparisonChain.start().
compare(_score,other.getScore()).
compare(_position,other.getPosition()).
compare(_bar,other.getBar(),BAR_COMPARATOR).
result();
}
privatestaticclassBarComparatorimplementsComparator<Bar>{
@Override
publicintcompare(Bara,Barb){
returna.toString().compareTo(b.toString());
}
}
}
4.提早编译正则表达式
字符串的操纵在Java中算是开支对照年夜的操纵。还好Java供应了一些工具让正则表达式尽量地高效。静态的正则表达式在理论中对照少见。在接上去要举的例子中,每次挪用String.replaceAll()都包括了一个常量形式使用到输出值中往。因而我们事后编译这个形式能够节俭CPU和内存的开支。
- 优化前:
1
2
3
privateStringtransform(Stringterm){
returnoutputTerm=term.replaceAll(_regex,_replacement);
}
- 优化后:
1
2
3
4
privatefinalPattern_pattern=Pattern.compile(_regex);
privateStringtransform(Stringterm){
StringoutputTerm=_pattern.matcher(term).replaceAll(_replacement);
}
5.尽量地缓存Cacheitifyoucan
将了局保留在缓存里也是一个制止过量开支的办法。但缓存只合用于在不异数据集撒花女人吗的不异数据操纵(好比对一些设置的预处置大概一些字符串处置)。如今已有多种LRU(LeastRecentlyUsed)缓存算法完成,可是Linkedin利用的是Guavacache(详细缘故原由见这里)大抵代码以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
privatefinalintMAX_ENTRIES=1000;
privatefinalLoadingCache<String,String>_cache;
//Initializingthecache
_cache=CacheBuilder.newBuilder().maximumSize(MAX_ENTRIES).build(newCacheLoader<String,String>(){
@Override
publicStringload(Stringkey)throwsException{
returnexpensiveOperationOn(key);
}
}
);
//Usingthecache
Stringoutput=_cache.getUnchecked(input);
6.String的intern办法有效,可是也有伤害
String的intern特征偶然候能够取代缓存来利用。
从这篇文档,我们能够晓得:
“Apoolofstrings,initiallyempty,ismaintainedprivatelybytheclassString.Whentheinternmethodisinvoked,ifthepoolalreadycontainsastringequaltothisStringobjectasdeterminedbytheequals(Object)method,thenthestringfromthepoolisreturned.Otherwise,thisStringobjectisaddedtothepoolandareferencetothisStringobjectisreturned”.
先谈谈我对java的一些认识。我选择java,是因为他语法简单,功能强大,从web,到桌面,到嵌入式,无所不能。但当我进一步了解了java后,感叹,java原来也有许多缺点。 |
|