在JAVA程序中,大部分的性能问题不是由JAVA语言引起的,而是程序本身引起的。养成良好的编码习惯非常重要,可以显着提高程序性能。《1.在合适的场合尽量使用单例》使用单例可以减轻加载负担,缩短加载时间,提高加载效率,但并不是所有的地方都适合单例。简单的说,单例主要适用于以下三个方面:控制资源的使用,通过线程同步控制对资源的并发访问;控制实例的生成,达到节省资源的目的;控制数据共享,并允许多个不相关的进程或线程之间进行通信。《2.尽量避免随意使用静态变量》当一个对象被定义为静态变量引用时,GC通常不会回收这个对象占用的内存,如:publicclassA{privatestaticBb=newB();}此时静态变量b的生命周期与类A的生命周期是同步的,如果类A不卸载,对象b会一直留在内存中,直到程序结束。《3.TrytoavoidcreatingtoomanyJavaobjectstoofrequent》尽量避免在频繁调用的方法和循环中产生新的对象,因为系统不仅要花时间创建对象,还要花时间对这些对象进行垃圾收集和处理,在我们的范围内可以最大程度的控制、复用对象,最好用基本数据类型或者数组来代替对象。《4.尽量使用final修饰符》带有final修饰符的类无法派生。在JAVA核心API中,有很多应用final的例子,比如java、lang、String。为String类指定final可防止用户覆盖length()方法。此外,如果一个类是最终的,则该类的所有方法都是最终的。java编译器会寻找机会内联(inline)所有的final方法(这个和具体的编译器实现有关),平均可以提高50%的性能。例如:将实例中访问变量的getter/setter方法设置为final:简单的getter/setter方法应该设置为final,这样会告诉编译器这个方法不会被重载,所以可以变成“inlined”“”,示例:类MAF{publicvoidsetSize(intsize){_size=size;}privateint_size;}//修正类DAF_fixed{finalpublicvoidsetSize(intsize){_size=size;}私人的;}int_size"5.尽量使用局部变量"调用方法时传递的参数和调用过程中创建的临时变量存储在栈(Stack)中,速度更快;其他的变量,比如静态变量、实例变量等,都是存放在堆(Heap)中,速度较慢。《6.尽量处理包装类型和基本类型的使用》虽然包装类型和基本类型在使用过程中可以相互转换,但是它们产生的内存区域是完全不同的。基本类型数据的生成和处理都是在栈中处理,包装类型是对象,在堆中生成实例。集合类对象中,对象需要的处理适用于包装类型,其他处理提倡使用基本类型。“7.谨慎使用synchronized,尽量减少synchronize的方法。”我们都知道同步需要大量的系统开销作为代价,甚至可能造成死锁,所以尽量避免不必要的同步控制。当调用synchronize方法时,会直接锁定当前对象,直到该方法执行完毕,其他线程才能调用当前对象的其他方法。因此,尽量减少synchronize的方法,尽量使用方法同步,而不是代码块同步。“9、尽量不要使用finalize方法。”事实上,将资源清理放在finalize方法中是一个非常糟糕的选择。因为GC的工作量很大,尤其是在回收Young代内存的时候,大部分的应用都会被挂起。因此,如果选择使用finalize方式来清理资源,会导致GC的负担更大,程序运行效率更差。"10.尽量使用基本数据类型而不是对象"Stringstr="hello";上面的方法会创建一个“hello”字符串,JVM的字符缓冲池也会缓存这个字符串;Stringstr=newString("你好");此时,str所引用的String对象底层除了创建了一个字符串外,还包含了一个char[]数组,依次存储了h,e,l,l,o。线程在没有线程安全的情况下尽量使用HashMap和ArrayList。HashTable、Vector等使用了同步机制,降低了性能。《12.尽可能合理地创建一个HashMap》当你想创建一个比较大的hashMap时,充分利用这个构造函数publicHashMap(intinitialCapacity,floatloadFactor);避免HashMap重复哈希重构,扩容是很重要的工作,对于消耗性能的东西,默认的initialCapacity只有16,loadFactor为0.75。需要多少容量?您最好准确估计您需要的最佳尺寸。Hashtable和Vectors也是如此。“13.尽量减少变量的重复计算”如:for(inti=0;i>2;intnum=a>>3;但要注意“使用shift时要加注解”,因为shift操作不直观,不易理解。《17、尽量使用shift而不是'a*b'运算》同样,对于'*'运算,使用shift运算会更快更高效,如:intnum=a*4;整数=a*8;应该改为:intnum=a<<2;intnum=a<<3;“18.尝试确定StringBuffer的容量”StringBuffer的构造函数将创建一个具有默认大小(通常为16)的字符数组。在使用中,如果超过这个大小,就会重新分配内存,创建一个更大的数组,复制原来的数组,丢弃旧的数组。大多数情况下,可以在创建StringBuffer时指定大小,避免容量不够时自动增长,提高性能。如:StringBufferbuffer=newStringBuffer(1000);《19.尽早释放对无用对象的引用》大多数时候,方法局部引用变量所引用的对象会随着方法结束而变成垃圾,所以大多数时候程序不需要显式地nulllocal,reference变量。例如:Java代码Publicvoidtest(){Objectobj=newObject();...obj=null;}上面的就不用了,随着test()方法执行完毕,程序中obj引用变量的作用域就结束了。但是如果改成下面这样:Java代码publicvoidtest(){Objectobj=newObject();...对象=空;//执行耗时耗内存的操作;或者调用耗时耗内存的方法...}这时候就需要将obj赋值为null,这样可以尽快释放对Object对象的引用。“20.尽量避免使用二维数组。”二维数据占用的内存空间比一维数组大得多,大约多10倍。《21.尽量避免使用split》除非必要,否则应该避免使用split。由于split支持正则表达式,所以效率比较低。如果是频繁的几十、上百万的调用,会消耗很多资源。如果确实需要经常调用split,可以考虑使用apache的StringUtils.split(string,char)。频繁拆分可以缓存结果。《22.ArrayList&LinkedList》一个是线性表,一个是链表,ArrayList优于LinkedList,LinkedList也需要移动指针,LinkedList的增删操作优于ArrayList,ArrayList需要移动数据,但这是理论上的分析。“23.尝试使用System.arraycopy()而不是循环复制数组”System.arraycopy()比循环复制数组快得多。《24.尽量缓存经常使用的对象》尽量缓存经常使用的对象,可以使用数组,或者HashMap容器??进行缓存,但是这种方式可能会导致系统占用过多的缓存,性能下降建议使用一些第三方开源工具,如EhCache、Oscache等进行缓存,基本实现了FIFO/FLU等缓存算法。“25.尽量避免非常大的内存分配”有时候问题不是由当时堆的状态引起的,而是分配失败造成的。所有分配的内存块必须是连续的,随着堆越来越满,找到更大的连续块变得越来越困难。《26.Useexceptionswithcaution》创建异常时,需要收集堆栈跟踪(stacktrack),用于描述异常创建的位置。构建这些堆栈跟踪需要拍摄运行时堆栈的快照,而这部分成本很高。当需要创建Exception时,JVM不得不说:别动,我要保存你现在的快照,所以暂时停止push和pop操作。堆栈跟踪不仅包括运行时堆栈中的一个或两个元素,还包括该堆栈中的每个元素。如果您创建Exception,则必须付出代价。好在捕获异常的开销不大,可以用try-catch来包裹核心内容。从技术上讲,您甚至可以随意抛出异常而无需付出太多代价。引发性能损失的不是throw操作——尽管在没有预先创建异常的情况下抛出异常有点不寻常。真正的成本是创建异常,幸运的是,良好的编程习惯告诉我们无论如何都不应该抛出异常。异常是为异常情况而设计的,使用时应牢记这一原则。《27.尽量重用对象》尤其是在String对象的使用中,出现字符串拼接时应该使用StringBuffer代替,因为系统不仅需要时间生成对象,还可能需要花时间进行垃圾回收和处理这些对象在未来。因此,生成过多的对象会对程序的性能产生很大的影响。《28.不要重复初始化变量》默认情况下,在调用类的构造函数时,java会将变量初始化为一定的值,所有对象都设置为null,整型变量设置为0,float和double变量设置为0.0,逻辑值设置为假。当一个类派生自另一个类时尤其如此,因为当使用new关键字创建对象时,会自动调用构造函数链中的所有构造函数。这里有一个注释。当为成员变量设置初始值但又需要调用其他方法时,最好放在一个方法中。比如在initXXX()中,因为直接调用了一个方法赋值,可能会因为类没有初始化而抛出空指针异常,如:publicintstate=this.getState()。「29」。在java+Oracle的应用系统开发中,java嵌入的SQL语言尽量使用大写,以减轻Oracle解析器的解析负担。“30”。在java编程过程中,进行数据库连接和I/O流操作,使用后及时关闭,释放资源。因为对这些大对象的操作会造成很大的系统开销。「31」。过多地创建对象会消耗系统大量的内存,严重时会导致内存泄漏。因此,保证过期对象的及时回收具有重要意义。JVM的GC不是很智能,所以建议在对象使用完后手动设置为null。“32、在使用同步机制时,尽量使用方法同步,而不是代码块同步。”“33.不要在循环中使用Try/Catch语句,try/Catch应该放在循环的最外层。”error是获取系统错误类,或者虚拟机错误类。并不是所有的错误Exception都可以获得。如果虚拟机报错Exception,则无法获取。必须使用错误来获取它。“34.通过StringBuffer的构造函数设置其初始化容量,可以显着提高性能。”StringBuffer的默认容量是16,当StringBuffer的容量达到最大容量时,它会增加容量到当前容量的2倍+2,即2*n+2。每当StringBuffer达到其最大容量时,它必须创建一个新的对象数组,然后复制旧的对象数组,这会浪费很多时间。所以有必要给StringBuffer设置一个合理的初始容量值!《35.java.util.Vector的合理使用》Vector类似于StringBuffer。每次扩容时,都必须将现有的所有元素分配到新的存储空间中。Vector默认存储容量为10个元素,扩容一倍。vector.add(index,obj)该方法可以将元素obj插入到index位置,但是index和后面的元素必须依次向下移动一个位置(将其index加1)。除非必要,否则对性能不利。相同的规则适用于remove(intindex)方法,该方法删除此向量中指定位置的元素。将所有后续元素向左移动(将其索引减1)。返回此向量中删除的元素。所以删除向量的最后一个元素比删除第一个元素便宜得多。最好使用removeAllElements()方法移除所有元素。如果你想删除vector中的一个元素,你可以使用vector.remove(obj);而不是自己检索元素的位置,然后删除它,比如intindex=indexOf(obj);矢量.删除(索引)。《38.不用new关键字创建对象的实例》当用new关键字创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但是如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。clone()方法不调用任何类构造函数。下面是工厂模式的典型实现:publicstaticCreditgetNewCredit(){returnnewCredit();}改进后的代码使用了clone()方法:publicstaticCreditgetNewCredit(){return(Credit)BaseCredit.clone();}"39.不要将数组声明为:publicstaticfinal""40.HaspMap的遍历":MapparaMap=newHashMap();for(Entryentry:paraMap.entrySet()){StringappFieldDefId=entry.getKey();String[]values=entry.getValue();}使用hash值获取对应的entry进行比较得到结果,获取到entry的value后直接获取key和value。《41.数组(array)和ArrayList的使用》array数组效率最高,但是它的容量是固定的,不能动态改变。ArrayList的容量可以动态增加,但是是以牺牲效率为代价的。「42」单线程尽量使用HashMap,ArrayList,HashTable,Vector非必要不推荐,它们使用了同步机制,会降低性能。“43”。StringBuffer和StringBuilder的区别在于:java.lang.StringBuffer是一个线程安全的可变字符序列。类似于String的字符串缓冲区,但不能修改。StringBuilderStringBuilder类通常应优先于此类使用,因为它支持所有相同的操作,但速度更快,因为它不执行同步。为了获得更好的性能,你应该在构造StringBuffer或StringBuilder时尽量指定她的容量。当然,如果不超过16个字符,就没有必要了。同等情况下,使用StringBuilder只能比使用StringBuffer获得10%~15%的性能提升,但又要承担多线程不安全的风险。综合考虑还是推荐使用StringBuffer。“44.尽量使用基本数据类型而不是对象。”“45”。使用具体类比使用接口更高效,但结构灵活性降低,但现代IDE可以解决这个问题。“46”。考虑使用静态方法。如果您不必访问对象的外部,则将您的方法设为静态方法。它会被调用得更快,因为它不需要虚函数指针表。这也是一个很好的做法,因为它告诉你如何区分方法的性质,调用这个方法不会改变对象的状态。“47.尽可能避免使用内部的GET和SET方法。”“48.避免枚举和使用浮点数。”》这里有几个实际优化的例子:》1.避免使用复杂在没有编译器优化的情况下,循环条件会在循环中反复计算,如果不使用复杂表达式,保持循环的值条件不变,程序会运行得更快。示例:importjava.util.Vector;classCEL{voidmethod(Vectorvector){for(inti=0;i10,Vector需要扩展for(inti=0;i