首页 java程序性能优化

java程序性能优化

举报
开通vip

java程序性能优化 一、避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循 环条件值不变的话,程序将会运行的更快。 例子: import java.util.vector; class cel { void method (vector vector) { for (int i = 0; i 10, vector needs to expand for (int i = ...

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 vector) { int size = vector.size () for (int i = 0; i < size; i++) ; // ... } } 二、为'vectors' 和 'hashtables'定义初始大小 jvm 为 vector 扩充大小的时候需要重新创建一个更大的数组,将原原先数组中的内容复制过 来,最后,原先的数组再被回收。可见 vector 容量的扩大是一个颇费时间的事。 通常,默认的 10 个元素大小是不够的。你最好能准确的估计你所需要的最佳大小。 例子: import java.util.vector; public class dic { public void addobjects (object[] o) { // if length > 10, vector needs to expand for (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 hashtable(10); 参考资料: dov bulka, "java performance and scalability volume 1: server-side programming techniques" addison wesley, isbn: 0-201-70429-3 pp.55 – 57 三、在 finally 块中关闭 stream 程序中使用到的资源应当被释放,以避免资源泄漏。这最好在 finally 块中去做。不管程序执行 的结果如何,finally 块总是会执行的,以确保资源的正确关闭。 例子: import java.io.*; public class cs { public static void main (string args[]) { cs cs = new cs (); cs.method (); } public void method () { try { fileinputstream fis = new fileinputstream ("cs.java"); int count = 0; while (fis.read () != -1) count++; system.out.println (count); fis.close (); } catch (filenotfoundexception e1) { } catch (ioexception e2) { } } } 更正: 在最后一个 catch 后添加一个 finally 块 参考资料: peter haggar: "practical java - programming language guide". addison wesley, 2000, pp.77-79 四、使用'system.arraycopy ()'代替通过来循环复制数组 'system.arraycopy ()' 要比通过循环来复制数组快的多。 例子: public class irb { void method () { int[] array1 = new int [100]; for (int i = 0; i < array1.length; i++) { array1 [i] = i; } int[] array2 = new int [100]; for (int i = 0; i < array2.length; i++) { array2 [i] = array1 [i]; // violation } } } 更正: public class irb { void method () { int[] array1 = new int [100]; for (int i = 0; i < array1.length; i++) { array1 [i] = i; } int[] array2 = new int [100]; system.arraycopy(array1, 0, array2, 0, 100); } } 参考资料: http://www.cs.cmu.edu/~jch/java/speed.html 五、让访问实例内变量的 getter/setter 方法变成”final” 简单的 getter/setter 方法应该被置成 final,这会告诉编译器,这个方法不会被重载,所以,可 以变成”inlined” 例子: class maf { public void setsize (int size) { _size = size; } private int _size; } 更正: class daf_fixed { final public void setsize (int size) { _size = size; } private int _size; } 参考资料: warren n. and bishop p. (1999), "java in practice", p. 4-5 addison-wesley, isbn 0-201-36065-9 六、避免不需要的 instanceof 操作 如果左边的对象的静态类型等于右边的,instanceof 表达式返回永远为 true。 例子: public class uiso { public uiso () {} } class dog extends uiso { void method (dog dog, uiso u) { dog d = dog; if (d instanceof uiso) // always true. system.out.println("dog is a uiso"); uiso uiso = u; if (uiso instanceof object) // always true. system.out.println("uiso is an object"); } } 更正: 删掉不需要的 instanceof 操作。 class dog extends uiso { void method () { dog d; system.out.println ("dog is an uiso"); system.out.println ("uiso is an uiso"); } } 七、避免不需要的造型操作 所有的类都是直接或者间接继承自 object。同样,所有的子类也都隐含的“等于”其父类。那么, 由子类造型至父类的操作就是不必要的了。 例子: class unc { string _id = "unc"; } class dog extends unc { void method () { dog dog = new dog (); unc animal = (unc)dog; // not necessary. object o = (object)dog; // not necessary. } } 更正: class dog extends unc { void method () { dog dog = new dog(); unc animal = dog; object o = dog; } } 参考资料: nigel warren, philip bishop: "java in practice - design styles and idioms for effective java". addison-wesley, 1999. pp.22-23 八、如果只是查找单个字符的话,用 charat()代替 startswith() 用一个字符作为参数调用 startswith()也会工作的很好,但从性能角度上来看,调用用 string api 无疑是错误的! 例子: public class pcts { private void method(string s) { if (s.startswith("a")) { // violation // ... } } } 更正 将'startswith()' 替换成'charat()'. public class pcts { private void method(string s) { if ('a' == s.charat(0)) { // ... } } } 参考资料: dov bulka, "java performance and scalability volume 1: server-side programming techniques" addison wesley, isbn: 0-201-70429-3 九、使用移位操作来代替'a / b'操作 "/"是一个很“昂贵”的操作,使用移位操作将会更快更有效。 例子: public class sdiv { public static final int num = 16; public void calculate(int a) { int div = a / 4; // should be replaced with "a >> 2". int div2 = a / 8; // should be replaced with "a >> 3". int temp = a / 3; } } 更正: public class sdiv { public static final int num = 16; public void calculate(int a) { int div = a >> 2; int div2 = a >> 3; int temp = a / 3; // 不能转换成位移操作 } } 十、使用移位操作代替'a * b' 同上。 [i]但我个人认为,除非是在一个非常大的循环内,性能非常重要,而且你很清楚你自己在做什 么,方可使用这种方法。否则提高性能所带来的程序晚读性的降低将是不合算的。 例子: public class smul { public void calculate(int a) { int mul = a * 4; // should be replaced with "a << 2". int mul2 = 8 * a; // should be replaced with "a << 3". int temp = a * 3; } } 更正: package opt; public class smul { public void calculate(int a) { int mul = a << 2; int mul2 = a << 3; int temp = a * 3; // 不能转换 } } 十一、在字符串相加的时候,使用 ' ' 代替 " ",如果该字符串只 有一个字符的话 例子: public class str { public void method(string s) { string string = s + "d" // violation. string = "abc" + "d" // violation. } } 更正: 将一个字符的字符串替换成' ' public class str { public void method(string s) { string string = s + 'd' string = "abc" + 'd' } } 十二、不要在循环中调用 synchronized(同步)方法 方法的同步需要消耗相当大的资料,在一个循环中调用它绝对不是一个好主意。 例子: import java.util.vector; public class syn { public synchronized void method (object o) { } private void test () { for (int i = 0; i < vector.size(); i++) { method (vector.elementat(i)); // violation } } private vector vector = new vector (5, 5); } 更正: 不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式: import java.util.vector; public class syn { public void method (object o) { } private void test () { synchronized{//在一个同步块中执行非同步方法 for (int i = 0; i < vector.size(); i++) { method (vector.elementat(i)); } } } private vector vector = new vector (5, 5); } 十三、将 try/catch 块移出循环 把 try/catch 块放入循环体内,会极大的影响性能,如果编译 jit 被关闭或者你所使用的是一个 不带 jit 的 jvm,性能会将下降 21%之多! 例子: import java.io.fileinputstream; public class try { void method (fileinputstream fis) { for (int i = 0; i < size; i++) { try { // violation _sum += fis.read(); } catch (exception e) {} } } private int _sum; } 更正: 将 try/catch 块移出循环 void method (fileinputstream fis) { try { for (int i = 0; i < size; i++) { _sum += fis.read(); } } catch (exception e) {} } 参考资料: peter haggar: "practical java - programming language guide". addison wesley, 2000, pp.81 – 83 十四、对于 boolean 值,避免不必要的等式判断 将一个 boolean 值与一个 true 比较是一个恒等操作(直接返回该 boolean 变量的值). 移走对于 boolean 的不必要操作至少会带来 2 个好处: 1)代码执行的更快 (生成的字节码少了 5 个字节); 2)代码也会更加干净 。 例子: public class ueq { boolean method (string string) { return string.endswith ("a") == true; // violation } } 更正: 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 不会再变的话,这将会减少运行开销提高性 能。 十六、用'stringtokenizer' 代替 'indexof()' 和'substring()' 字符串的 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 在很多应用中都是常见的。使用 indexof()和 substring()来分析字符串容易导致 stringindexoutofboundsexception。而使用 stringtokenizer 类来分析字符串则会容易一 些,效率也会高一些。 例子: public class ust { void parsestring(string string) { int index = 0; while ((index = string.indexof(".", index)) != -1) { system.out.println (string.substring(index, string.length())); } } } 参考资料: graig larman, rhett guthrie: "java 2 performance and idiom guide" prentice hall ptr, isbn: 0-13-014260-3 pp. 282 – 283 十七、使用条件操作符替代"if (cond) return; else return;" 结构 条件操作符更加的简捷 例子: public class if { public int method(boolean isdone) { if (isdone) { return 0; } else { return 10; } } } 更正: public class if { public int method(boolean isdone) { return (isdone ? 0 : 10); } } 十八、使用条件操作符代替"if (cond) a = b; else a = c;" 结 构 例子: public class ifas { void method(boolean istrue) { if (istrue) { _value = 0; } else { _value = 1; } } private int _value = 0; } 更正: public class ifas { void method(boolean istrue) { _value = (istrue ? 0 : 1); // compact expression. } private int _value = 0; } 十九、不要在循环体中实例化变量 在循环体中实例化临时变量将会增加内存消耗 例子: import java.util.vector; public class loop { void method (vector v) { for (int i=0;i < v.size();i++) { object o = new object(); o = v.elementat(i); } } } 更正: 在循环体外定义变量,并反复使用 import java.util.vector; public class loop { void method (vector v) { object o; for (int i=0;i 快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题 的大部分原因并不在于 JAVA 语言,而是程序本身。养 成良好的编码习惯非常重要,能够显著地提升程序性能。 1. 尽量使用 final 修饰符。 带有 final 修饰符的类是不可派生的。在 JAVA 核心 API 中,有许多应用 final 的例子,例如 java.lang.String。为 String 类指定 final 防止了使用者覆盖 length()方法。另外,如果一个 类是 final 的,则该类所有方法都是 final 的。java 编译器会寻找机会内联(inline)所有的 final 方法(这和具体的编译器实现有关)。此举能够使性能平均提高 50%。 2.尽量重用对象。 特别是 String 对象的使用中,出现字符串连接情况时应使用 StringBuffer 代替,由于系统不仅 要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理。因此生成过多的对 象将会给程序的性能带来很大的影响。 3. 尽量使用局部变量。 调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他 变量,如静态变量,实例变量等,都在堆(Heap)中创建,速度较慢。 4.不要重复初始化变量。 默认情况下,调用类的构造函数时,java 会把变量初始化成确定的值,所有的对象被设置成 null,整数变量设置成 0,float 和 double 变量设置成 0.0,逻辑值设置成 false。当一个类从 另一个类派生时,这一点尤其应该注意,因为用 new 关键字创建一个对象时,构造函数链中的 所有构造函数都会被自动调用。 这里有个注意,给成员变量设置初始值但需要调用其他方法的时候,最好放在一个方法比如 initXXX()中,因为直接调用某方法赋值可能会因为类尚未初始化而抛空指针异常,public int state = this.getState(); 5.在 java+Oracle 的应用系统开发中,java 中内嵌的 SQL 语言应尽量使用大写形式,以减少 Oracle 解析器的解析负担。 6.java 编程过程中,进行数据库连接,I/O 流操作,在使用完毕后,及时关闭以释放资源。因为 对这些大对象的操作会造成系统大的开销。 7.过分的创建对象会消耗系统的大量内存,严重时,会导致内存泄漏,因此,保证过期的对象的 及时回收具有重要意义。 JVM 的 GC 并非十分智能,因此建议在对象使用完毕后,手动设置成 null。 8.在使用同步机制时,应尽量使用方法同步代替代码块同步。 9.尽量减少对变量的重复计算。 比如 for(int i=0;i paraMap = new HashMap(); for( Entry entry : paraMap.entrySet() ) { String appFieldDefId = entry.getKey(); String[] values = entry.getValue(); } 利用散列值取出相应的 Entry 做比较得到结果,取得 entry 的值之后直接取 key 和 value。 21.array(数组)和 ArrayList 的使用。 array 数组效率最高,但容量固定,无法动态改变,ArrayList 容量可以动态增长,但牺牲了效 率。 22.单线程应尽量使用 HashMap, ArrayList,除非必要,否则不推荐使用 HashTable,Vector, 她们使用了同步机制,而降低了性能。 23.StringBuffer,StringBuilder 的区别在于:java.lang.StringBuffer 线程安全的可变字符 序列。一个类似于 String 的字符串缓冲区,但不能修改。StringBuilder 与该类相比,通常应 该优先使用 StringBuilder 类,因为她支持所有相同的操作,但由于她不执行同步,所以速度更 快。为了获得更好的性能,在构造 StringBuffer 或 StringBuilder 时应尽量指定她的容量。当 然如果不超过 16 个字符时就不用了。 相同情况下,使用 StringBuilder 比使用 StringBuffer 仅能获得 10%~15%的性能提升,但 却要冒多线程不安全的风险。综合考虑还是建议使用 StringBuffer。 24. 尽量使用基本数据类型代替对象。 25.用简单的数值计算代替复杂的函数计算,比如查表方式解决三角函数问题。 26.使用具体类比使用接口效率高,但结构弹性降低了,但现代 IDE 都可以解决这个问题。 27.考虑使用静态方法, 如果你没有必要去访问对象的外部,那么就使你的方法成为静态方法。她会被更快地调用,因为 她不需要一个虚拟函数导向表。这同事也是一个很好的实践,因为她告诉你如何区分方法的性 质,调用这个方法不会改变对象的状态。 28.应尽可能避免使用内在的 GET,SET 方法。 android 编程中,虚方法的调用会产生很多代价,比实例属性查询的代价还要多。我们应该在外 包调用的时候才使用 get,set 方法,但在内部调用的时候,应该直接调用。 29. 避免枚举,浮点数的使用。 30.二维数组比一维数组占用更多的内存空间,大概是 10 倍计算。 31.SQLite 数据库读取整张表的全部数据很快,但有条件的查询就要耗时 30-50MS,大家做这方 面的时候要注意,尽量少用,尤其是嵌套查找! [/size][align=left][/align] 《java 解惑》转 文章分类:Java 编程 转载于:http://jiangzhengjun.javaeye.com/blog/652623 数值表达式 1. 奇偶判断 不要使用 i % 2 == 1 来判断是否是奇数,因为 i 为负奇数时不成立, 请使用 i % 2 != 0 来判断是否是奇数,或使用 高效式 (i & 1) != 0 来判断。 2. 小数精确计算 System.out.println(2.00 -1.10);//0.8999999999999999 上面的计算出的结果不是 0.9,而是一连串的小数。问题在于 1.1 这个数字不能被精确表示为一 个 double,因此它被表 示为最接近它的 double 值,该程序从 2 中减去的就是这个值,但这个计算的结果并不是最接近 0.9 的 double 值。 一般地说,问题在于并不是所有的小数都可以用二进制浮点数精确表示。 二进制浮点对于货币计算是非常不适合的,因为它不可能将 1.0 表示成 10 的其他任何负次幂。 解决问题的第一种方式是使用货币的最小单位(分)来表示: System.out.println(200-110);//90 第二种方式是使用 BigDecimal,但一定要用 BigDecimal(String)构造器,而千万不要用 BigDecimal(double)来构造(也不能将 float 或 double 型转换成 String 再来使用 BigDecimal(String)来构造,因为在将 float 或 double 转换成 String 时精度已丢失)。 例如 new BigDecimal(0.1), 它将返回一个 BigDecimal, 也即 0.1000000000000000055511151231257827021181583404541015625, 正确使用 BigDecimal,程序就可以打印出我们所期 望的结果 0.9: System.out.println(new BigDecimal("2.0").subtract(new BigDecimal("1.10")));// 0.9 另外,如果要比较两个浮点数的大小,要使用 BigDecimal 的 compareTo 方法。 3. int 整数相乘溢出 我们计算一天中的微秒数: long microsPerDay = 24 * 60 * 60 * 1000 * 1000;// 正确结果应为:86400000000 System.out.println(microsPerDay);// 实际上为:500654080 问题在于计算过程中溢出了。这个计算式完全是以 int 运算来执行的,并且只有在运算完成之 后,其结果才被提升为 long,而此时已经太迟:计算已经溢出。 解决方法使计算表达式的第一个因子明确为 long 型,这样可以强制表达式中所有的后续计算 都用 long 运算来完成,这样结果就不会溢出: long microsPerDay = 24L * 60 * 60 * 1000 * 1000; 4. 负的十六进制与八进制字面常量 “数字字面常量”的类型都是 int 型,而不管他们是几进制,所以“2147483648”、 “0x180000000(十六进制,共 33 位,所以超过了整数的取值范围)”字面常量是错误的,编
本文档为【java程序性能优化】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_615387
暂无简介~
格式:pdf
大小:382KB
软件:PDF阅读器
页数:25
分类:互联网
上传时间:2012-06-29
浏览量:141