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