Java程序性能优化23条.docx

上传人:b****1 文档编号:723584 上传时间:2023-04-29 格式:DOCX 页数:22 大小:20.27KB
下载 相关 举报
Java程序性能优化23条.docx_第1页
第1页 / 共22页
Java程序性能优化23条.docx_第2页
第2页 / 共22页
Java程序性能优化23条.docx_第3页
第3页 / 共22页
Java程序性能优化23条.docx_第4页
第4页 / 共22页
Java程序性能优化23条.docx_第5页
第5页 / 共22页
Java程序性能优化23条.docx_第6页
第6页 / 共22页
Java程序性能优化23条.docx_第7页
第7页 / 共22页
Java程序性能优化23条.docx_第8页
第8页 / 共22页
Java程序性能优化23条.docx_第9页
第9页 / 共22页
Java程序性能优化23条.docx_第10页
第10页 / 共22页
Java程序性能优化23条.docx_第11页
第11页 / 共22页
Java程序性能优化23条.docx_第12页
第12页 / 共22页
Java程序性能优化23条.docx_第13页
第13页 / 共22页
Java程序性能优化23条.docx_第14页
第14页 / 共22页
Java程序性能优化23条.docx_第15页
第15页 / 共22页
Java程序性能优化23条.docx_第16页
第16页 / 共22页
Java程序性能优化23条.docx_第17页
第17页 / 共22页
Java程序性能优化23条.docx_第18页
第18页 / 共22页
Java程序性能优化23条.docx_第19页
第19页 / 共22页
Java程序性能优化23条.docx_第20页
第20页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

Java程序性能优化23条.docx

《Java程序性能优化23条.docx》由会员分享,可在线阅读,更多相关《Java程序性能优化23条.docx(22页珍藏版)》请在冰点文库上搜索。

Java程序性能优化23条.docx

Java程序性能优化23条

Java程序性能优化

一、避免在循环条件中使用复杂表达式

在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。

例子:

importjava.util.Vector;

classCEL{

voidmethod(Vectorvector){

for(inti=0;i

;//...

}

}

更正:

classCEL_fixed{

voidmethod(Vectorvector){

intsize=vector.size()

for(inti=0;i

;//...

}

}

 

二、为'Vectors'和'Hashtables'定义初始大小

JVM为Vector扩充大小的时候需要重新创建一个更大的数组,将原原先数组中的内容复制过来,最后,原先的数组再被回收。

可见Vector容量的扩大是一个颇费时间的事。

通常,默认的10个元素大小是不够的。

你最好能准确的估计你所需要的最佳大小。

例子:

importjava.util.Vector;

publicclassDIC{

publicvoidaddObjects(Object[]o){

//iflength>10,Vectorneedstoexpand

for(inti=0;i

v.add(o);//capacitybeforeitcanaddmoreelements.

}

}

publicVectorv=newVector();//noinitialCapacity.

}

更正:

自己设定初始大小。

publicVectorv=newVector(20);

publicHashtablehash=newHashtable(10);

参考资料:

DovBulka,"JavaPerformanceandScalabilityVolume1:

Server-SideProgramming

Techniques"AddisonWesley,ISBN:

0-201-70429-3pp.55–57

 

三、在finally块中关闭Stream

程序中使用到的资源应当被释放,以避免资源泄漏。

这最好在finally块中去做。

不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。

例子:

importjava.io.*;

publicclassCS{

publicstaticvoidmain(Stringargs[]){

CScs=newCS();

cs.method();

}

publicvoidmethod(){

try{

FileInputStreamfis=newFileInputStream("CS.java");

intcount=0;

while(fis.read()!

=-1)

count++;

System.out.println(count);

fis.close();

}catch(FileNotFoundExceptione1){

}catch(IOExceptione2){

}

}

}

更正:

在最后一个catch后添加一个finally块

参考资料:

PeterHaggar:

"PracticalJava-ProgrammingLanguageGuide".

AddisonWesley,2000,pp.77-79

四、使用'System.arraycopy()'代替通过来循环复制数组

'System.arraycopy()'要比通过循环来复制数组快的多。

例子:

publicclassIRB

{

voidmethod(){

int[]array1=newint[100];

for(inti=0;i

array1[i]=i;

}

int[]array2=newint[100];

for(inti=0;i

array2[i]=array1[i];//Violation

}

}

}

更正:

publicclassIRB

{

voidmethod(){

int[]array1=newint[100];

for(inti=0;i

array1[i]=i;

}

int[]array2=newint[100];

System.arraycopy(array1,0,array2,0,100);

}

}

参考资料:

http:

//www.cs.cmu.edu/~jch/java/speed.html

 

五、让访问实例内变量的getter/setter方法变成”final”

简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,所以,可以变成”inlined”

例子:

classMAF{

publicvoidsetSize(intsize){

_size=size;

}

privateint_size;

}

更正:

classDAF_fixed{

finalpublicvoidsetSize(intsize){

_size=size;

}

privateint_size;

}

参考资料:

WarrenN.andBishopP.(1999),"JavainPractice",p.4-5

Addison-Wesley,ISBN0-201-36065-9

 

六、避免不需要的instanceof操作

如果左边的对象的静态类型等于右边的,instanceof表达式返回永远为true。

例子:

publicclassUISO{

publicUISO(){}

}

classDogextendsUISO{

voidmethod(Dogdog,UISOu){

Dogd=dog;

if(dinstanceofUISO)//alwaystrue.

System.out.println("DogisaUISO");

UISOuiso=u;

if(uisoinstanceofObject)//alwaystrue.

System.out.println("uisoisanObject");

}

}

更正:

删掉不需要的instanceof操作。

classDogextendsUISO{

voidmethod(){

Dogd;

System.out.println("DogisanUISO");

System.out.println("UISOisanUISO");

}

}

 

七、避免不需要的造型操作

所有的类都是直接或者间接继承自Object。

同样,所有的子类也都隐含的“等于”其父类。

那么,由子类造型至父类的操作就是不必要的了。

例子:

classUNC{

String_id="UNC";

}

classDogextendsUNC{

voidmethod(){

Dogdog=newDog();

UNCanimal=(UNC)dog;//notnecessary.

Objecto=(Object)dog;//notnecessary.

}

}

更正:

classDogextendsUNC{

voidmethod(){

Dogdog=newDog();

UNCanimal=dog;

Objecto=dog;

}

}

参考资料:

NigelWarren,PhilipBishop:

"JavainPractice-DesignStylesandIdioms

forEffectiveJava".Addison-Wesley,1999.pp.22-23

八、如果只是查找单个字符的话,用charAt()代替startsWith()

用一个字符作为参数调用startsWith()也会工作的很好,但从性能角度上来看,调用用StringAPI无疑是错误的!

例子:

publicclassPCTS{

privatevoidmethod(Strings){

if(s.startsWith("a")){//violation

//...

}

}

}

更正

将'startsWith()'替换成'charAt()'.

publicclassPCTS{

privatevoidmethod(Strings){

if('a'==s.charAt(0)){

//...

}

}

}

参考资料:

DovBulka,"JavaPerformanceandScalabilityVolume1:

Server-SideProgramming

Techniques"AddisonWesley,ISBN:

0-201-70429-3

九、使用移位操作来代替'a/b'操作

"/"是一个很“昂贵”的操作,使用移位操作将会更快更有效。

例子:

publicclassSDIV{

publicstaticfinalintNUM=16;

publicvoidcalculate(inta){

intdiv=a/4;//shouldbereplacedwith"a>>2".

intdiv2=a/8;//shouldbereplacedwith"a>>3".

inttemp=a/3;

}

}

更正:

publicclassSDIV{

publicstaticfinalintNUM=16;

publicvoidcalculate(inta){

intdiv=a>>2;

intdiv2=a>>3;

inttemp=a/3;//不能转换成位移操作

}

}

 

十、使用移位操作代替'a*b'

同上。

[i]但我个人认为,除非是在一个非常大的循环内,性能非常重要,而且你很清楚你自己在做什么,方可使用这种方法。

否则提高性能所带来的程序晚读性的降低将是不合算的。

例子:

publicclassSMUL{

publicvoidcalculate(inta){

intmul=a*4;//shouldbereplacedwith"a<<2".

intmul2=8*a;//shouldbereplacedwith"a<<3".

inttemp=a*3;

}

}

更正:

packageOPT;

publicclassSMUL{

publicvoidcalculate(inta){

intmul=a<<2;

intmul2=a<<3;

inttemp=a*3;//不能转换

}

}

 

十一、在字符串相加的时候,使用''代替"",如果该字符串只有一个字符的话

 

例子:

publicclassSTR{

publicvoidmethod(Strings){

Stringstring=s+"d"//violation.

string="abc"+"d"//violation.

}

}

更正:

将一个字符的字符串替换成''

publicclassSTR{

publicvoidmethod(Strings){

Stringstring=s+'d'

string="abc"+'d'

}

}

 

十二、不要在循环中调用synchronized(同步)方法

方法的同步需要消耗相当大的资料,在一个循环中调用它绝对不是一个好主意。

例子:

importjava.util.Vector;

publicclassSYN{

publicsynchronizedvoidmethod(Objecto){

}

privatevoidtest(){

for(inti=0;i

method(vector.elementAt(i));//violation

}

}

privateVectorvector=newVector(5,5);

}

更正:

不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式:

importjava.util.Vector;

publicclassSYN{

publicvoidmethod(Objecto){

}

privatevoidtest(){

synchronized{//在一个同步块中执行非同步方法

for(inti=0;i

method(vector.elementAt(i));

}

}

}

privateVectorvector=newVector(5,5);

}

 

十三、将try/catch块移出循环

把try/catch块放入循环体内,会极大的影响性能,如果编译JIT被关闭或者你所使用的是一个不带JIT的JVM,性能会将下降21%之多!

例子:

importjava.io.FileInputStream;

publicclassTRY{

voidmethod(FileInputStreamfis){

for(inti=0;i

try{//violation

_sum+=fis.read();

}catch(Exceptione){}

}

}

privateint_sum;

}

更正:

将try/catch块移出循环

voidmethod(FileInputStreamfis){

try{

for(inti=0;i

_sum+=fis.read();

}

}catch(Exceptione){}

}

参考资料:

PeterHaggar:

"PracticalJava-ProgrammingLanguageGuide".

AddisonWesley,2000,pp.81–83

 

十四、对于boolean值,避免不必要的等式判断

将一个boolean值与一个true比较是一个恒等操作(直接返回该boolean变量的值).移走对于boolean的不必要操作至少会带来2个好处:

1)代码执行的更快(生成的字节码少了5个字节);

2)代码也会更加干净。

例子:

publicclassUEQ

{

booleanmethod(Stringstring){

returnstring.endsWith("a")==true;//Violation

}

}

更正:

classUEQ_fixed

{

booleanmethod(Stringstring){

returnstring.endsWith("a");

}

}

 

十五、对于常量字符串,用'String'代替'StringBuffer'

常量字符串并不需要动态改变长度。

例子:

publicclassUSC{

Stringmethod(){

StringBuffers=newStringBuffer("Hello");

Stringt=s+"World!

";

returnt;

}

}

更正:

把StringBuffer换成String,如果确定这个String不会再变的话,这将会减少运行开销提高性能。

 

十六、用'StringTokenizer'代替'indexOf()'和'substring()'

字符串的分析在很多应用中都是常见的。

使用indexOf()和substring()来分析字符串容易导致StringIndexOutOfBoundsException。

而使用StringTokenizer类来分析字符串则会容易一些,效率也会高一些。

例子:

publicclassUST{

voidparseString(Stringstring){

intindex=0;

while((index=string.indexOf(".",index))!

=-1){

System.out.println(string.substring(index,string.length()));

}

}

}

参考资料:

GraigLarman,RhettGuthrie:

"Java2PerformanceandIdiomGuide"

PrenticeHallPTR,ISBN:

0-13-014260-3pp.282–283

 

十七、使用条件操作符替代"if(cond)return;elsereturn;"结构

条件操作符更加的简捷

例子:

publicclassIF{

publicintmethod(booleanisDone){

if(isDone){

return0;

}else{

return10;

}

}

}

更正:

publicclassIF{

publicintmethod(booleanisDone){

return(isDone?

0:

10);

}

}

十八、使用条件操作符代替"if(cond)a=b;elsea=c;"结构

例子:

publicclassIFAS{

voidmethod(booleanisTrue){

if(isTrue){

_value=0;

}else{

_value=1;

}

}

privateint_value=0;

}

更正:

publicclassIFAS{

voidmethod(booleanisTrue){

_value=(isTrue?

0:

1);//compactexpression.

}

privateint_value=0;

}

 

十九、不要在循环体中实例化变量

在循环体中实例化临时变量将会增加内存消耗

例子:

importjava.util.Vector;

publicclassLOOP{

voidmethod(Vectorv){

for(inti=0;i

Objecto=newObject();

o=v.elementAt(i);

}

}

}

更正:

在循环体外定义变量,并反复使用

importjava.util.Vector;

publicclassLOOP{

voidmethod(Vectorv){

Objecto;

for(inti=0;i

o=v.elementAt(i);

}

}

}

 

二十、确定StringBuffer的容量

StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。

在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。

在大多数情况下,你可以在创建StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。

例子:

publicclassRSBC{

voidmethod(){

StringBufferbuffer=newStringBuffer();//violation

buffer.append("hello");

}

}

更正:

为StringBuffer提供寝大小。

publicclassRSBC{

voidmethod(){

StringBufferbuffer=newStringBuffer(MAX);

buffer.append("hello");

}

privatefinalintMAX=100;

}

参考资料:

DovBulka,"JavaPerformanceandScalabilityVolume1:

Server-SideProgramming

Techniques"AddisonWesley,ISBN:

0-201-70429-3p.30–31

 

二十一、尽可能的使用栈变量

如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。

static?

local?

还是实例变量?

访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。

例子:

publicclassUSV{

voidgetSum(int[]values){

for(inti=0;i

_sum+=value[i];//violation.

}

}

voidg

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 临时分类 > 批量上传

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2