《2022年Java程序优化大全 .pdf》由会员分享,可在线阅读,更多相关《2022年Java程序优化大全 .pdf(21页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、Java 程序优化大全颜色说明颜色说明*橙色 * 重点优化对象,必须遵守。*黑色 * 能够提高性能,建议使用,但是不强制要求。一、避免在循环条件中使用复杂表达式在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。例子:import java.util.Vector; class CEL void method(Vector vector) for ( int i = 0; i vector.size(); i+) / Violation ; / . 更正:class CEL_fixed void method (Vector
2、 vector) int size = vector.size(); for ( int i = 0; i 10, Vector needs to expandfor ( int i = 0; i o.length; i+) v .add(o); / capacity before it can add more elements. public Vector v = new Vector(); / no initialCapacity. 更正:自己设定初始大小。 public Vector v = new Vector(20); public Hashtable hash = new Has
3、htable(10); 三、在 finally 块中关闭数据库连接、I/O 流操作,以释放资源程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally 块中去做。不管程序执行的结果如何,finally 块总是会执行的,以确保资源的正确关闭。例子:import java.io.*; publicclass CS publicstaticvoid main(String args) CS cs = new CS(); cs.method(); publicvoid method() 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - -
4、 - - 名师精心整理 - - - - - - - 第 2 页,共 21 页 - - - - - - - - - FileInputStream fis = null; try fis = new FileInputStream(CS.java); int count = 0; while (fis.read() != -1) count+; System.out.println(count); catch (FileNotFoundException e1) catch (IOException e2) finally fis.close(); 四、使用 System.arraycopy (
5、) 代替通过来循环复制数组System.arraycopy () 要比通过循环来复制数组快的多。例子:publicclass IRB void method() int array1 = newint100; for ( int i = 0; i array1.length; i+) array1 = i; int array2 = newint100; for ( int i = 0; i array2.length; i+) array2 = array1; / Violation 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - -
6、 - 名师精心整理 - - - - - - - 第 3 页,共 21 页 - - - - - - - - - 更正:publicclass IRB void method() int array1 = newint100; for ( int i = 0; i 2.int div2 = a / 8; / should be replaced with a 3.int temp = a / 3; 更正:publicclass SDIV publicstaticfinalintNUM = 16; publicvoid calculate(int a) int div = a 2; int div2
7、 = a 3; int temp = a / 3; / 不能转换成位移操作 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 21 页 - - - - - - - - - 十、使用移位操作代替a * b 同上。但我个人认为, 除非是在一个非常大的循环内,性能非常重要, 而且你很清楚你自己在做什么,方可使用这种方法。否则提高性能所带来的程序晚读性的降低将是不合算的。例子:publicclass SMUL publicvoid calculate(int a) int mul
8、= a * 4; / should be replaced with a 2.int mul2 = 8 * a; / should be replaced with a 3.int temp = a * 3; 更正:package OPT; publicclass SMUL publicvoid calculate(int a) int mul = a 2; int mul2 = a 3; int temp = a * 3; / 不能转换 十一、在字符串相加的时候,使用 代替 ,如果该字符串只有一个字符的话例子:public class STR public void method(Strin
9、g s) String string = s + d / violation. 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 21 页 - - - - - - - - - string = abc + d / violation. 更正:将一个字符的字符串替换成 public class STR public void method(String s) String string = s + d string = abc + d 十二、不要在循环中调用synchroni
10、zed(同步 )方法方法的同步需要消耗相当大的资料,在一个循环中调用它绝对不是一个好主意。例子:import java.util.Vector; publicclass SYN publicsynchronizedvoid method(Object o) privatevoid test() for ( int i = 0; i vector.size(); i+) method(vector.elementAt(i); / violation private Vector vector = new Vector(5, 5); 更正:不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式
11、:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 21 页 - - - - - - - - - import java.util.Vector; publicclass SYN publicvoid method(Object o) privatevoid test () synchronized /在一个同步块中执行非同步方法for ( int i = 0; i vector.size(); i+) method (vector.elementAt(i); privat
12、e Vector vector = new Vector(5, 5); 十三、将 try/catch 块移出循环把 try/catch 块放入循环体内,会极大的影响性能,如果编译 JIT 被关闭或者你所使用的是一个不带 JIT 的 JVM ,性能会将下降21%之多 ! 例子:import java.io.FileInputStream; publicclass TRY void method(FileInputStream fis) for ( int i = 0; i size; i+) try / violation_sum += fis.read(); 名师资料总结 - - -精品资料欢
13、迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 21 页 - - - - - - - - - catch (Exception e) privateint_sum ; 更正:将 try/catch 块移出循环void method (FileInputStream fis) try for ( int i = 0; i size; i+) _sum += fis.read(); catch (Exception e) 十四、对于 boolean值,避免不必要的等式判断将一个 boolean 值与一个tr
14、ue 比较是一个恒等操作(直接返回该boolean 变量的值 ). 移走对于boolean 的不必要操作至少会带来2 个好处:1)代码执行的更快(生成的字节码少了5 个字节 );2)代码也会更加干净。例子:public class UEQ boolean method (String string) return string.endsWith (a) = true; / Violation 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 21 页 - - - - -
15、- - - - 更正:class UEQ_fixed boolean method (String string) return string.endsWith (a); 十五、对于常量字符串,用String 代替StringBuffer 常量字符串并不需要动态改变长度。例子:public class USC String method () StringBuffer s = new StringBuffer (Hello); String t = s + World!; return t; 更正:把 StringBuffer 换成 String,如果确定这个String 不会再变的话,这将会
16、减少运行开销提高性能。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 21 页 - - - - - - - - - 十六、用StringTokenizer 代替indexOf() 和substring() 字符串的分析在很多应用中都是常见的。使用 indexOf() 和 substring()来分析字符串容易导致StringIndexOutOfBoundsException 。而使用StringTokenizer 类来分析字符串则会容易一些,效率也会高一些。例子:pub
17、licclass UST void parseString(String string) int index = 0; while (index = string.indexOf(., index) != -1) System.out .println(string.substring(index, string.length(); 十七、不要在循环体中实例化变量在循环体中实例化临时变量将会增加内存消耗例子:import java.util.Vector; publicclass LOOP void method(Vector v) for ( int i = 0; i v.size(); i
18、+) Object o = new Object(); o = v.elementAt(i); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 13 页,共 21 页 - - - - - - - - - 更正:在循环体外定义变量,并反复使用import java.util.Vector; publicclass LOOP void method(Vector v) Object o; for ( int i = 0; i v.size(); i+) o = v.elementAt(i
19、); 十八、确定StringBuffer 的容量StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建StringBuffer 的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。例子:publicclass RSBC void method() StringBuffer buffer = new StringBuffer(); / violation buffer.append(hello); 更正:为 StringBuff
20、er 提供大小。publicclass RSBC void method() StringBuffer buffer = new StringBuffer(MAX); buffer.append(hello); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 14 页,共 21 页 - - - - - - - - - privatefinalintMAX = 100; 十九、尽可能的使用栈变量如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static? local?还
21、是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3 个时钟周期。例子:publicclass USV void getSum(int values) for ( int i = 0; i value.length; i+) _sum += value; / violation. void getSum2(int values) for ( int i = 0; i value.length; i+) _staticSum += value; privateint_sum ; privatestaticint_staticSum; 更正:如果可能,请使用局部变量作为你经常访问的变量
22、。你可以按下面的方法来修改getSum()方法:void getSum (int values) int sum = _sum; / temporary local variable.for (int i=0; i value.length; i+) sum += value; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 15 页,共 21 页 - - - - - - - - - _sum = sum; 二十、不要总是使用取反操作符(!) 取反操作符 (!)降低程序的可读性,所以
23、不要总是使用。例子:publicclass test boolean method(boolean a, boolean b) if (!a) return !a; else return !b; 更正:如果可能不要使用取反操作符(!) 二十一、与一个接口进行instanceof操作基于接口的设计通常是件好事,因为它允许有不同的实现,而又保持灵活。只要可能, 对一个对象进行instanceof 操作,以判断它是否某一接口要比是否某一个类要快。例子:public class INSOF private void method (Object o) if (o instanceof Interfa
24、ceBase) / better if (o instanceof ClassBase) / worse. 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 16 页,共 21 页 - - - - - - - - - class ClassBase interface InterfaceBase 二十二、异常对性能不利抛出异常首先要创建一个新的对象。Throwable 接口的构造函数调用名为fillInStackTrace()的本地( Native)方法, fillInStackTra
25、ce() 方法检查堆栈,收集调用跟踪信息。只要有异常被抛出, VM 就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。异常只能用于错误处理,不应该用来控制程序流程。二十三、不用 new 关键词创建类的实例用 new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。 clone()方法不会调用任何类构造函数。在使用设计模式 (Design Pattern )的场合, 如果用 Factory模式创建对象, 则改用 clone()方法创建新的对象实例非常简单。例如,下面是Factory 模式的一个典型
26、实现:publicstatic Credit getNewCredit() returnnew Credit(); 改进后的代码使用clone()方法,如下所示:private static Credit BaseCredit = new Credit(); public static Credit getNewCredit() return (Credit) BaseCredit.clone(); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 17 页,共 21 页 - - -
27、- - - - - - 二十四、尽量使用局部变量调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack )中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap )中创建,速度较慢。二十五、避免对象创建和GC 只要有可能, 应该避免创建对象,防止调用构造函数带来的相关性能成本,以及在对象结束其生命周期时进行垃圾收集所带来的成本。考虑以下这些准则:只要有可能,就 使用基本变量类型,而不使用对象类型。例如,使用int,而不使用Integer ;缓存那些频繁使用的寿命短的对象,避免一遍又一遍地重复创建相同的对象,并因此加重垃圾收集的负担;在处理字符串时,使用 StringBu
28、ffer 而不使用字符串String 进行连接操作, 因为字符串对象具有不可变的特性,并且需要创建额外的字符串对象以完成相应的操作,而这些对象最终必须经历GC;避免过度地进行Java 控制台的写操作,降低字符串对象处理、文本格式化和输出带来的成本;实现数据库连接池,重用连接对象,而不是重复地打开和关闭连接;使用线程池( thread pooling ),避免不停地创建和删除线程对象,特别是在大量使用线程的时候;避免在代码中调用GC。GC 是一个 “ 停止所有处理(stop the world )” 的事件,它意味着除了GC 线程自身外,其他所有执行线程都将处于挂起状态。如果必须调用GC,那么可
29、以在非紧急阶段或空闲阶段实现它;避免在循环内分配对象。尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope )后,自动设置为null 。我们在使用这种方式时候,必须特别注意一些复杂的对象,例如数组,队列,树,图等,这些对象之间的相互引用关名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 18 页,共 21 页 - - - - - - - - - 系较为复杂。对于这类对象,GC 回收它们一般效率较低。如果程序允许,尽早将不再使用的引用对象赋为n
30、ull。这样可以加速GC 的工作。如果有经常使用的图片,可以使用soft 引用类型。它可以尽可能将图片保存在内存中,供程序调用,而不引起Out Of Memory。注意一些全局的变量,以及一些静态变量。这些变量往往容易引起悬挂对象(dangling reference),造成内存浪费。使用String a = a ;定义字符串,而不是使用String a = new String( a );二十六、避免非常大的分配有时候问题不是由当时的堆状态造成的,而是因为分配失败造成的。分配的内存块都必须是连续的,而随着堆越来越满,找到较大的连续块越来越困难。这不仅仅是Java 的问题,使用C 中的 mal
31、loc 也会遇到这个问题。JVM 在压缩阶段通过重新分配引用来减少碎片,但其代价是要冻结应用程序较长的时间。二十七、SQL 语句大写在 JAVA + ORACLE 的应用系统开发中,java 中内嵌的SQL 语句尽量使用大写的形式,以减轻 ORACLE 解析器的解析负担。二十八、尽量重用对象,特别是String 对象的使用中,出现字符串连接情况时应用StringBuffer 代替由于系统不仅要花时间生成对象,以后可能还需花时间对这些对象进行垃圾回收和处理。因此,生成过多的对象将会给程序的性能带来很大的影响;例子:StringBuffer sqlbuff = new StringBuffer()
32、; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 19 页,共 21 页 - - - - - - - - - sqlbuff.append( select to_char(decode(parent_item_id ,(select parent_item_id from s_finance_item_2009 where item_id=10),null,parent_item_id) up_id, + to_char(item_id) id,item_name name );
33、sqlbuff.append( from s_finance_item_2009 start with item_id=10 connect by parent_item_id= prior item_id ); 二十九、由于 JVM 的有其自身的GC 机制,不需要程序开发者的过多考虑,从一定程度上减轻了开发者负担,但同时也遗漏了隐患, 过分的创建对象会消耗系统的大量内存,严重时会导致内存泄露;JVM 回收垃圾的条件是:对象不在被引用;然而,JVM 的 GC 并非十分的机智,即使对象满足了垃圾回收的条件也不一定会被立即回收。所以,建议我们在对象使用完毕,应手动置成null ;示例代码:Obje
34、ct rvo = new Object2; ArrayList tlist = new ArrayList(); tlist = BOQueryResult.getInstence().getQueryResult(sql, BOQueryResult.integrateSqlAgent); if (tlist.size() = 1) rvo = (Object) tlist.get(0); /对象使用完毕,手工释放对象 tlist = null; return rvo; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心
35、整理 - - - - - - - 第 20 页,共 21 页 - - - - - - - - - 三十、尽量使用 HashMap 和 ArrayList , 除非必要,否则不推荐使用HashTable 和 Vector ,后者由于使用同步机制,而导致了性能的开销;三十一、array( 数组 ) 和 ArryList 的使用array() :最高效;但是其容量固定且无法动态改变;ArrayList :容量可动态增长;但牺牲效率;基于效率和类型检验,应尽可能使用array,无法确定数组大小时才使用ArrayList !ArrayList 是 Array 的复杂版本ArrayList 内部封装了一个
36、Object 类型的数组, 从一般的意义来说,它和数组没有本质的差别,甚至于ArrayList 的许多方法,如Index、IndexOf 、Contains、 Sort 等都是在内部数组的基础上直接调用Array 的对应方法。ArrayList 存入对象时,抛弃类型信息,所有对象屏蔽为Object,编译时不检查类型,但是运行时会报错。注: jdk5 中加入了对泛型的支持,已经可以在使用ArrayList 时进行类型检查。从这一点上看来,ArrayList 与数组的区别主要就是由于动态增容的效率问题了;三十二、在进行金额计算时使用BigDecimal 对于帐务系统中金额处理的运行,一律采用BigDecimal 。转换元为分 BigDecimal money = new BigDecimal(100); money = money.movePointLeft(2); 处理结果为:1.00 转换分为元 BigDecimal money = new BigDecimal(100); money = money.movePointRight(2); 处理结果为:10000名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 21 页,共 21 页 - - - - - - - - -