Java开发规范及性能优化

代码优化,可能提及来一些人以为没用.但是我以为应该平时开发过程当中,就尽可能要求本身,养成良好习惯,一个个小的优化点,积攒起来绝对是有大幅度效率提高的。java

代码优化目标:算法

1.減小代码体积数据库

2.提升整个系统的运行效率,代码细节忧化编程

3.尽可能指定类,方法的final修饰符,带有final修饰符的类是不可派生的,在Java核心APl中,有许多应用final的例子,例如java.lang.string,整个类都是finaI的.为类指定final修饰符可让类不能够被继承,为方法指定finaI可让方法不能够被重写,若是指定一个类为finaI,该类的全部方法都是final的- Java编译器会寻找机会内联全部的final方法,内联对于提高Java运行效率做用重大,具体参见Java這行期优化,此举可以提高性能平均50%。数组

4. 尽可能重用对象安全

特别是 string对象的使用,出现字特申連接时应该使用 StringBuilder/StringBuffer代替-因为 Java虚拟机不只要花时间生成对象,之后可能还须要花时间对这些对象进行垃圾回收和处理,所以,,生成过多的对象将会给程序的性能带来很大的影响,并发

5.尽量使用局部対象app

调用方法时传選的參数以及在调用中创jvm

建的临时变量都保存在浅中速度较快,,其余变量,如静态变量、实例变量等,,都在堆中建立,速度较慢-另外, 栈中建立的变量,随着方法的运行结東,,这些内容就没了,不须要额外的垃圾回收,函数

6. 及时关闭流

Java编程中, 进行数据库链接、l/o流操做时务必当心,在使用完毕后,及时关闭以释放資源-由于对这些大对象的操做会形成系统大的开销,稍有不慎,将会致使严重的后果。

7. 尽可能减小对变量的重复计算

明确一个概念,对方法的调用,即便方法中只有一句语句,也是有消耗的,包括建立栈帧、调用方法时保护现场、调用方法完毕时恢复现场等-因此例以下面的操做:

for(int i= 01 i< list.size0; i++)

{_}建议答換为, for(int i= 0, int length= list.size(); i< length; i++) {_}这样,在list.size0很大的时候.就減少了不少的消耗

八、尽可能采用懒加载的策略.即在须要的时候才建立

例如:String str= "aaa";

if(i== 1) {

list.add(str); }建议替換为:  if(i== l) {String str= •aaan;

list.add(str); }

九、慎用异常

异常对性能不利-抛出异常首先要建立一个新的对象,  Throwable接口的构造函数调用名为 filllnstackrrace0的本地同步方法,  filllnstackrrace0方法检査栈堆,收集调用跟踪信息-只要有异常被抛出, Java虚拟机就必须调整调用栈堆,由于在处理过程当中建立了一个新的对象-异常只能用于错误处理,不该该用来控制程序流程。

十、不要在循环中使用try_catch_ ,应该把其放在最外,除非不得已-若是毫无理由地这么写了,只要你的领导資深一点、有强追症一点,八成就要骂你为何写出这种垃圾代码来了。

十一、若是能估计到带加的内容长度,为底层以数组方式实現的集合、 工具类指定初始长度

好比ArrayList、 LinkedLlist、StringBuiIder、 StringBufler、HashMap、 HashSet等等,以StringBuilder为例:

(l) StringBuilder//般认分配l6个字符的空间

(2) StringBuilder(int size) //默认分配size个字符的空间

(3) StringBuilder(String str) //般认分配l6个字符+str.length个字符空间,能够经过类(这里指的不只仅是上面的

stringBuilder)的来设定它的初始化容量, 这样能够明显地提高性能-好比StringBuilder吧, length表示当前的stringBuilder能保持的字待数量.由于当stringBuilder达到最大容量的时候,它会将自身容量增长到当前的2倍再加2 , 不管什么时候只要stringBuilder达到它的最大容量, 它就不得不建立一个新的字符数组而后将l日的字符数组内容拷贝到新字符数组中一一这是十分耗费性能的一个操做-试想,若是能预估到字符数组中大概要存放5ooo个字符而不指定长度,最接近5ooo的2次幂是4o96,每次扩容加的2 无论,那么:

(l)在4096的基础上.再申请 8194个大小的字符数组,加起来至关于一次申清了l229o个大小的字符数组,若是一开始能指定5ooo个大小的字特数组,就节省了一倍以上的空间

(2)把原来的4o96个字符持贝到新的的字特数组中去、这样,既浪费内存空间,又下降代得运行效率-因此,给底层以数组实現的集合、工具类设置一个合理的初始化容量是不错的,这会带来立竿见影的效果-可是,注意,像HashMap这种是以数组+链表实现的集合, 别把初始大小和你估计的大小设置得同样,由于一个table上只連接一个对象的可能性几乎为o,初始大小建议设置为2的N次幂,若是能估计到有2ooo个元素,设置成new HashMap(l28)、 new HashMap(256) 均可以。

一样道理,应尽量的以指明容量大小的方式对ArrayList进行实例化

public ArrayList();默认的构造器,JAVA以10个元素的大小初始化

public ArrayList(int);用指定的容量大小大小初始化

不指明容量大小时,如集合容量不够,则JAVA会以1.5倍的容量递增扩充,并且每次扩充,系统会从新拷贝一遍已经加入到ArrayList的数据,从而致使额外的内存开销。

补充:使用StringBuilder来链接字符串

有不少不一样的选项来链接Java中的字符串。例如,您可使用简单的+或+ =,StringBuffer或一个StringBuilder。

那么,你应该选择哪一种方法?

答案取决于链接字符串的代码。若是以编程方式将新内容添加到字符串中,例如在for循环中,则应使用StringBuilder。它很容易使用,并提供比StringBuffer更好的性能。但请记住,与StringBuffer相比,StringBuilder不是线程安全的,可能不适合全部用例。

你只须要实例化一个新的StringBuilder并调用append方法来向String中添加一个新的部分。而当你添加了全部的部分,你能够调用toString()方法来检索链接的字符串。

有不少不一样的选项来链接Java中的字符串。例如,您可使用简单的+或+ =,StringBuffer或一个StringBuilder。

那么,你应该选择哪一种方法?

答案取决于链接字符串的代码。若是以编程方式将新内容添加到字符串中,例如在for循环中,则应使用StringBuilder。它很容易使用,并提供比StringBuffer更好的性能。但请记住,与StringBuffer相比,StringBuilder不是线程安全的,可能不适合全部用例。

你只须要实例化一个新的StringBuilder并调用append方法来向String中添加一个新的部分。而当你添加了全部的部分,你能够调用toString()方法来检索链接的字符串。

在一个语句中使用+链接字符串

当你用Java实现你的第一个应用程序时,可能有人告诉过你不该该用+来链接字符串。 若是您在应用程序逻辑中链接字符串,这是正确的。 字符串是不可变的,每一个字符串链接的结果都存储在一个新的String对象中。 这须要额外的内存,并减慢你的应用程序,特别是若是你在一个循环内链接多个字符串。

在这些状况下,您应该遵循上面的规则并使用StringBuilder。

可是,若是您只是将字符串分红多行来改善代码的可读性,状况并不是如此。

Java性能调优准则(绝对干货)

在这些状况下,你应该用一个简单的+来链接你的字符串。 您的Java编译器将优化这个并在编译时执行链接。 因此,在运行时,你的代码将只使用1个字符串,不须要链接。

 

十二、当复制大量数据时,使用 System.arraycopy()命令

1三、乘法和除法使用移位操做

例如: for(val= 0; val< l00000; val +=5){a=val*8:b=val/2;}用移位操做能够极大地提升性能,由于在计算机底层,对位的操做是最方便、最快的,所以建议修改成: for(val= o:val<100000; val+= 5) { a=val << 3; b = val>> 1;}移位操做星然快,可是可能会使代码不太好理解,所以最好加上相应的注释

1四、循环内不要不断建立对象引用及不要在循环体内声明变量

例如: for(inti= l:i<=count; i++) {0bject obj= new 〇bject0; }这种作法会致使内存中有count份object对象引用存在, count很大的话,就耗费内存了,,建议为改成: 〇bject obj= null;for(int i= 01 i<=count; i十十) {obj= new object0; }这样的话,内存中只有一份Object对象引用,每次new完object0的时候, Object对象引用指向不一样的0bject 罢了,可是内存中只有一份, 这样就大大节省了内存空间 -

l五、基于效率和类型检査的考虑, 应该尽量使用array,没法肯定数组大小时才使用ArrayList

l六、 尽可能使用HashMap、 ArrayList、stringBuilder,除非线程安全须要,不然不推荐使用Hashtable、 Vector、stringBuffer,后三者因为使用同步机制而致使了性能开销

l七、不要将数组声明为 public static final由于这室无心义, 这样只是定义了引用为 static final, 数组的内容仍是能够随意改变的,将数组声明为 public更是一个安全構洞,这意味着这个数组能够被外部类所改变

l八、 尽可能在合适的场合使用单例

使用单例能够減轻加裁的负担、结短加载的时间、提升加裁的效率,但并非全部地方都适用于単例,笛単来讲,単例主要适用于如下三个方面:

(l)控制資源的使用,经过线程同步来控制資源的并发访问

(2)控制实例的产生,以达到节约資源的目的

(3)控制数据的共事,在不创建直接关联的条件下,让多个不相关的进程或线程之间实現通讯

1九、 尽可能进免随意使用静态变量

要知道,当某个对象被定义为 static的变量所引用,那么 gc一般是不会回收这个対象所占有的堆内存的,如:

public class A{private static B b= new B0; }

20、避免使用包装类构造函数

按照SUN公司的说明,使用自动装箱或静态工厂方法比使用new一个对象快3到4倍,该规则能够用在valueOf或其它静态工厂的调用中(如:Short、Integer, Long、Double, Byte 、Boolean等)。

public static void main(String args[]){
        //不推荐写法
        int a=new Integer(100);
        System.out.println(a);
        //虽然这对于jvm来讲,体现不出来明显效果。
        //推荐写法
        int b=Integer.valueOf(100);
        System.out.println(b);
    }

2一、面向接口编程时,推荐使用接口的声明方式

为何要用 List list = new ArrayList() ,而不用 ArrayList alist = new ArrayList()呢? 
问题就在于List有多个实现类,如今你用的是ArrayList,也许哪一天你须要换成其它的实现类,如 LinkedList或者Vector等等,这时你只要改变这一行就好了: 
List list = new LinkedList(); 其它使用了list地方的代码根本不须要改动。 
假设你开始用 ArrayList alist = new ArrayList(), 这下你有的改了,特别是若是你使用了 ArrayList特有的方法和属性。

List list = new ArrayList();这句建立了一个ArrayList的对象后把上溯到了List。此时它是一个List对象了,有些ArrayList有可是List没有的属性和方法,它就不能再用了。 
而ArrayList list=new ArrayList();建立一对象则保留了ArrayList的全部属性。 

List list = new ArrayList(); 
ArrayList arrayList = new ArrayList();
list.trimToSize(); //错误,没有该方法。
arrayList.trimToSize();   //ArrayList里有该方法。

2二、单个方法代码行数尽可能保持在80-100行以内

2三、数据库及磁盘IO等操做,必须在try-catch-finally块的finally中执行close()方法

若有多个对象须要关闭,则须分别对每一个对象的close()方法进行try-catch,以防止出现一个对象关闭失败而致使其余对象都未关闭的状况出现

2四、不要在循环体内进行数据库的“链接-关闭”操做

若有大批量的数据须要修改,建议使用PreparedStatement的Batch功能(一次性发送多个操做给数据库)

2五、大量(如超过五次以上的“+=”运算)的字符串操做应使用StringBuilder或StringBuffer,尽可能避免使用String

2六、不要在循环条件中使用表达式

2七、集合中的数据若是不使用了应该及时释放

因为集合保存了对象的引用,虚拟机的垃圾收集器就不会回收

2八、非正常运行产生的异常被捕获后,必须对异常进行处理

在非finally块代码中catch的异常应该从新抛出通过封装的异常,在finally中再次catch的异常不该该再次抛出,应该写日志。不管是抛出异常仍是记录日志,都要传递异常对象。日志应记录详细的描述信息,避免调用异常对象的getMessage()方法,直接将该异常对象做为参数传递。

2九、尽可能定位异常类型,不要一概catch(Exception ex)

当须要在某些出口捕获全部可能出现的运行时异常或Error时,能够catch Exception 或Throwable,尽可能避免一个方法中一个大的try块,catch一个Exception的代码方式,若是有必要可使用多个try-catch块分别处理

30、不要将赋值运算符用在容易与相等关系运算符混淆的地方,如:咱们可将“if (a == b && c == d)”改成可读性更强的“if ((a == b) && (c == d)) ”,可将“x >= 0 ? x : -x;"改成”(x >= 0) ? x : -x;

3一、尽量使用基本数据

避免任何开销并提升应用程序性能的另外一种简便快速的方法是使用基本类型而不是其包装类。 因此,最好使用int来代替Integer,或者使用double来代替Double。 这容许您的JVM将值存储在栈而不是在堆中,以减小内存消耗,并更高效地处理它。

3二、尽可能避免使用BigInteger和BigDecimal

因为咱们已经在讨论数据类型,因此咱们也应该快速浏览一下BigInteger和BigDecimal。 尤为是后者因其精确性而受欢迎。 可是这是有代价的。

BigInteger和BigDecimal须要更多的内存比一个long或double,而且看起来会下降全部的运行效率。 因此,若是你须要额外的精度,或者若是你的数字将超过一个长的范围,最好三思。 这多是您须要更改以解决性能问题的惟一方法,特别是在实施数学算法时。

3三、使用Apache Commons的StringUtils.Replace来替代String.replace

通常来讲,String.replace方法工做正常,效率很高,尤为是在使用Java 9的状况下。可是,若是您的应用程序须要大量的替换操做,而且没有更新到最新的Java版本,那么它仍然是有意义的 检查更快和更有效的替代品。

一个候选项是Apache Commons Lang的StringUtils.replace方法。 正如Lukas Eder在他最近的一篇博客文章中所描述的,它远远超过了Java 8的String.replace方法。

并且这只须要很小的改动。 您须要将Apache的Commons Lang项目的Maven依赖项添加到您的应用程序pom.xml中,并将String.replace方法的全部调用替换为StringUtils.replace方法。

相关文章
相关标签/搜索