35个Java代码性能优化总结

上传人:宝路 文档编号:23250251 上传时间:2017-11-30 格式:DOCX 页数:34 大小:171.08KB
返回 下载 相关 举报
35个Java代码性能优化总结_第1页
第1页 / 共34页
35个Java代码性能优化总结_第2页
第2页 / 共34页
35个Java代码性能优化总结_第3页
第3页 / 共34页
35个Java代码性能优化总结_第4页
第4页 / 共34页
35个Java代码性能优化总结_第5页
第5页 / 共34页
点击查看更多>>
资源描述

《35个Java代码性能优化总结》由会员分享,可在线阅读,更多相关《35个Java代码性能优化总结(34页珍藏版)》请在金锄头文库上搜索。

1、前言代码优化,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是,吃的小虾米一多之后,鲸鱼就被喂饱了。代码优化也是一样,如果项目着眼于尽快无 BUG 上线,那么此时可以抓大放小,代码的细节可以不精打细磨;但是如果有足够的时间开发、维护代码,这时候就必须考虑每个可以优化的细节了,一个一个细小的优化点累积起来,对于代码的运行效率绝对是有提升的。代码优化的目标是:1、减小代码的体积2、提高代码运行的效率本文的内容有些来自网络,有些来自平时工作和学习,当然这不重要,

2、重要的是这些代码优化的细节是否真真正正地有用。那本文会保持长期更新,只要有遇到值得分享的代码优化细节,就会不定时地更新此文。代码优化细节1、尽量指定类、方法的 final 修饰符带有 final 修饰符的类是不可派生的。在 Java 核心 API 中,有许多应用final 的例子,例如 java.lang.String,整个类都是 final 的。为类指定 final 修饰符可以让类不可以被继承,为方法指定 final 修饰符可以让方法不可以被重写。如果指定了一个类为 final,则该类所有的方法都是 final 的。Java 编译器会寻找机会内联所有的 final 方法,内联对于提升 Jav

3、a 运行效率作用重大,具体参见 Java 运行期优化。此举能够使性能平均提高 50%。2、尽量重用对象特别是 String 对象的使用,出现字符串连接时应该使用StringBuilder/StringBuffer 代替。由于 Java 虚拟机不仅要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理,因此,生成过多的对象将会给程序的性能带来很大的影响。3、尽可能使用局部变量调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中速度较快,其他变量,如静态变量、实例变量等,都在堆中创建,速度较慢。另外,栈中创建的变量,随着方法的运行结束,这些内容就没了,不需要额外的垃圾回收。4、及

4、时关闭流Java 编程过程中,进行数据库连接、 I/O 流操作时务必小心,在使用完毕后,及时关闭以释放资源。因为对这些大对象的操作会造成系统大的开销,稍有不慎,将会导致严重的后果。5、尽量减少对变量的重复计算明确一个概念,对方法的调用,即使方法中只有一句语句,也是有消耗的,包括创建栈帧、调用方法时保护现场、调用方法完毕时恢复现场等。所以例如下面的操作:for(inti=0;i1;移位操作虽然快,但是可能会使代码不太好理解,因此最好加上相应的注释。12、循环内不要不断创建对象引用例如:for(inti=1;iiterator=list.iterable();while(iterator.hasN

5、ext()iterator.next()foreach 循环的底层实现原理就是迭代器 Iterator,参见 Java 语法糖 1:可变长度参数以及 foreach 循环原理。所以后半句 反过来,如果是顺序访问的,则使用 Iterator 会效率更高 的意思就是顺序访问的那些类实例,使用 foreach循环去遍历。20、使用同步代码块替代同步方法这点在多线程模块中的 synchronized 锁方法块一文中已经讲得很清楚了,除非能确定一整个方法都是需要进行同步的,否则尽量使用同步代码块,避免对那些不需要进行同步的代码也进行了同步,影响了代码执行效率。21、将常量声明为 staticfinal,

6、并以大写命名这样在编译期间就可以把这些内容放入常量池中,避免运行期间计算生成常量的值。另外,将常量的名字以大写命名也可以方便区分出常量与变量22、不要创建一些不使用的对象,不要导入一些不使用的类这毫无意义,如果代码中出现Thevalueofthelocalvariableiisnotused、Theimportjava.utilisneverused,那么请删除这些无用的内容23、程序运行过程中避免使用反射关于,请参见反射。反射是 Java 提供给用户一个很强大的功能,功能强大往往意味着效率不高。不建议在程序运行过程中使用尤其是频繁使用反射机制,特别是 Method 的 invoke 方法,如

7、果确实有必要,一种建议性的做法是将那些需要通过反射加载的类在项目启动的时候通过反射实例化出一个对象并放入内存-用户只关心和对端交互的时候获取最快的响应速度,并不关心对端的项目启动花多久时间。24、使用数据库连接池和线程池这两个池都是用于重用对象的,前者可以避免频繁地打开和关闭连接,后者可以避免频繁地创建和销毁线程25、使用带缓冲的输入输出流进行 IO 操作带缓冲的输入输出流,即BufferedReader、BufferedWriter 、BufferedInputStream、BufferedOutputStream,这可以极大地提升 IO 效率26、顺序插入和随机访问比较多的场景使用 Arr

8、ayList,元素删除和中间插入比较多的场景使用 LinkedList这个,理解 ArrayList 和 LinkedList 的原理就知道了27、不要让 public 方法中有太多的形参public 方法即对外提供的方法,如果给这些方法太多形参的话主要有两点坏处:1、违反了面向对象的编程思想,Java 讲求一切都是对象,太多的形参,和面向对象的编程思想并不契合2、参数太多势必导致方法调用的出错概率增加至于这个太多 指的是多少个, 3、4 个吧。比如我们用 JDBC 写一个insertStudentInfo 方法,有 10 个学生信息字段要插如 Student 表中,可以把这 10 个参数封装

9、在一个实体类中,作为 insert 方法的形参28、字符串变量和字符串常量 equals 的时候将字符串常量写在前面这是一个比较常见的小技巧了,如果有以下代码:Stringstr=123;if(str.equals(123).建议修改为:Stringstr=123;if(123.equals(str).这么做主要是可以避免空指针异常29、请知道,在 java 中 if(i=1)和 if(1=i)是没有区别的,但从阅读习惯上讲,建议使用前者平时有人问,if(i=1)和if(1=i) 有没有区别,这就要从 C/C+讲起。在 C/C+中,if(i=1)判断条件成立,是以 0 与非 0 为基准的,0

10、表示false,非 0 表示 true,如果有这么一段代码:inti=2;if(i=1).else.C/C+判断 i=1不成立,所以以 0 表示,即 false。但是如果:inti=2;if(i=1).else.万一程序员一个不小心,把if(i=1)写成if(i=1),这样就有问题了。在if 之内将 i 赋值为 1,if 判断里面的内容非 0,返回的就是 true 了,但是明明 i为 2,比较的值是 1,应该返回的 false。这种情况在 C/C+的开发中是很可能发生的并且会导致一些难以理解的错误产生,所以,为了避免开发者在 if 语句中不正确的赋值操作,建议将 if 语句写为:inti=2;

11、if(1=i).else.这样,即使开发者不小心写成了1=i,C/C+编译器也可以第一时间检查出来,因为我们可以对一个变量赋值 i 为 1,但是不能对一个常量赋值 1 为i。但是,在 Java 中,C/C+这种if(i=1)的语法是不可能出现的,因为一旦写了这种语法,Java 就会编译报错Typemismatch:cannotconvertfrominttoboolean。但是,尽管 Java 的if(i=1)和 if(1=i)在语义上没有任何区别,但是从阅读习惯上讲,建议使用前者会更好些。30、不要对数组使用 toString()方法看一下对数组使用 toString()打印出来的是什么:p

12、ublicstaticvoidmain(Stringargs)intis=newint1,2,3;System.out.println(is.toString();结果是:I18a992f本意是想打印出数组内容,却有可能因为数组引用 is 为空而导致空指针异常。不过虽然对数组 toString()没有意义,但是对集合 toString()是可以打印出集合里面的内容的,因为集合的父类 AbstractCollections重写了 Object的 toString()方法。32、不要对超出范围的基本数据类型做向下强制转型这绝不会得到想要的结果:publicstaticvoidmain(String

13、args)longl=12345678901234L;inti=(int)l;System.out.println(i);我们可能期望得到其中的某几位,但是结果却是:1942892530解释一下。Java 中 long 是 8 个字节 64 位的,所以 12345678901234 在计算机中的表示应该是:0000000000000000000010110011101001110011110011100010111111110010一个 int 型数据是 4 个字节 32 位的,从低位取出上面这串二进制数据的前32 位是:01110011110011100010111111110010这串二进

14、制表示为十进制 1942892530,所以就是我们上面的控制台上输出的内容。从这个例子上还能顺便得到两个结论:1、整型默认的数据类型是 int,longl=12345678901234L,这个数字已经超出了 int 的范围了,所以最后有一个 L,表示这是一个 long 型数。顺便,浮点型的默认类型是 double,所以定义 float 的时候要写成floatf=3.5f2、接下来再写一句intii=l+i;会报错,因为 long+int 是一个 long,不能赋值给 int33、公用的集合类中不使用的数据一定要及时 remove 掉如果一个集合类是公用的(也就是说不是方法里面的属性),那么这个

15、集合里面的元素是不会自动释放的,因为始终有引用指向它们。所以,如果公用集合里面的某些数据不使用而不去 remove 掉它们,那么将会造成这个公用集合不断增大,使得系统有内存泄露的隐患。34、把一个基本数据类型转为字符串,基本数据类型.toString()是最快的方式、String.valueOf(数据)次之、数据+最慢把一个基本数据类型转为一般有三种方式,我有一个 Integer 型数据 i,可以使用 i.toString()、String.valueOf(i)、i+三种方式,三种方式的效率如何,看一个测试:publicstaticvoidmain(Stringargs)intloopTime=50000;Integeri=0;longstartTime=System.currentTimeMillis();for(intj=0;jhm=newHashMap();hm.put(111,222);SetentrySet=hm.entrySet();Iteratoriter=entrySet.iterator();while(iter.hasNext()Map.Entryentry=iter.next();System.out.println(entry.getKe

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号