java代码优化总结

  1. 减少对变量的重复计算--》for循环的优化

    for (int i = 0; i < args.length; i++) {

    

    }

更改为:

    for (int i = 0,index=args.length; i < index; i++) {

    

    }

原理:每次在i++的时候都会重新计算一次args.length,优化之后只会计算一次

2.  底层使用可变数组的数据结构尽量指定长度

例如最常用的ArrayList,HashMap

List list = new ArrayList<>(10);

Map map = new HashMap<>(10);

3. String类尽量使用StringBuffer、StringBuilder

例如:

String str = “abc”;

String str2 = str + “ccd”;

jvm会在堆内存中开辟3个空间,1为“abc”,2为“ccd”,3为“abcccd”,最终str2指向,1和2因为没有被引用,会在GC回收机制内被回收,而GC的开销是相当大的,所以应尽量避免。

使用StringBuffer:

StringBuffer str =“abc”;  

str.append(“ccd”);

jvm只会在堆空间中开辟一个空间“abc”,执行append时只会在“abc”的空间上+“ccd”

因此避免了GC的回收,也避免了内存的浪费

如果有线程安全的考虑使用StringBuffer,无则使用StringBuilder,线程安全也是一个比较高的开销

4. 使用equals()方法时常量尽量写前面

例如:

    Brand brand = new Brand();

     brand.setImgUrl("dddddddddd");

    // brand.setName("HFanss");

     String ss = "HFanss";

     if (brand.getName().equals(ss)) {

    System.err.println("相同");

    }else

    {

        System.err.println("不相同");

    }

抛出空指针异常,应修改为:

 if (ss.equals(brand.getName()))

这时候会输出   不相同。

原理:equals的源码解释 当比较对象(常量ss)为空时,抛出空指针异常,

而被比较对象(brand.getName())为空时,则直接以 false结束

5. 尽量采用懒加载的策略,就是在需要的时候才创建

如:

    String str = "HFanss";

     if ("2".equals(status)) {

            list.add(str);

      }

应该为:

    if ("2".equals(status)) {

      String str = "HFanss";

      list.add(str);

   }

原理:这个应该很容易看懂的,当if不成立时,创建的字符串就没用了,面临GC回收,应该有效避免,写在if内部

6. 在数值运算时,遇到偶数乘、除偶数倍时,尽量使用位移运算(不做要求)

如:

    int a = 2;

    

    int b = 16;

    

    System.err.println(a<<5);//等同于  2*2*2*2*2*2   即2*32

    

System.err.println(b>>2);//等同于  16/2/2      即16/4

 

7. 对象引用的优化

如:

    List list = new ArrayList<>();

    for (int i = 0; i < 1000; i++)

    {

        Object obj  = new Object();   

    

        list.add(obj);

    }

应该为:

    List list = new ArrayList<>();

    

    Object obj = null;

    

    for (int i = 0; i < 1000; i++)

    {

        obj  = new Object();   

        list.add(obj);

    

    }

原理:我们的目的只是list.add(obj)这一步,

前者obj引用会在栈空间中有1000个,但是最终只会用到1个,

后者obj引用在栈空间只有1个

8. 尽量避免随意使用静态变量 (根据实际业务情况)

当某个对象被定义为static变量所引用,那么GC通常是不会回收这个对象所占有的内存,如

 

public class A{

 

private static B b = new B();

 

}

 

此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。

 

9. 尽量使用final修饰符

带有final修饰符的类是不可派生的。在JAVA核心API中,有许多应用final的例子,例如java、lang、String,为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关),此举能够使性能平均提高50%。

 

如:让访问实例内变量的getter/setter方法变成”final:

 

简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,例子:

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;

 

}

 

10. 将变量不为空转换成字符串时尽量使用to.string()方法

一般有3种方法

    Integer s = 5;

    

    s.toString();//s为null报空指针异常

    String.valueOf(s);//源码显示调用了Integer.toString()方法,而且会在调用前做空判断

s+“”;//源码显示使用StringBuilder实现,先用append方法拼接,再用toString()方法对比而言,直接调用最底层的toString()方法无疑是效率最高的

11. 尽量使用System.arraycopy ()代替通过来循环复制数组

System.arraycopy() 要比通过循环来复制数组快的多。

12. HaspMap的遍历

Map paraMap = new HashMap();

 

for( Entry entry : paraMap.entrySet() )

 

{

 

String appFieldDefId = entry.getKey();

 

String[] values = entry.getValue();

 

}

利用散列值取出相应的Entry做比较得到结果,取得entry的值之后直接取key和value。

13. 尽量使用基本数据类型代替对象

String str = "hello";

上面这种方式会创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;

String str = new String("hello");

此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o

14. 尽量早释放无用对象的引用

大部分时,方法局部引用变量所引用的对象会随着方法结束而变成垃圾,因此,大部分时候程序无需将局部,引用变量显式设为null。

 

例如:

 

Public void test(){

 

Object obj = new Object();

 

……

 

Obj=null;

 

}

 

上面这个就没必要了,随着方法test()的执行完成,程序中obj引用变量的作用域就结束了。但是如果是改成下面:

 

Public void test(){

 

Object obj = new Object();

 

……

 

Obj=null;

 

//执行耗时,耗内存操作;或调用耗时,耗内存的方法

 

……

 

}

这时候就有必要将obj赋值为null,可以尽早的释放对Object对象的引用。

15. 尽量避免使用split

除非是必须的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需要频繁的调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。

16. 不要重复初始化变量

默认情况下,调用类的构造函数时,java会把变量初始化成确定的值,所有的对象被设置成null,整数变量设置成0,float和double变量设置成0.0,逻辑值设置成false。当一个类从另一个类派生时,这一点尤其应该注意,因为用new关键字创建一个对象时,构造函数链中的所有构造函数都会被自动调用。

 

这里有个注意,给成员变量设置初始值但需要调用其他方法的时候,最好放在一个方法。比如initXXX()中,因为直接调用某方法赋值可能会因为类尚未初始化而抛空指针异常,如:public int state = this.getState()。

17. 不要在循环中使用Try/Catch语句,应把Try/Catch放在循环最外层

Error是获取系统错误的类,或者说是虚拟机错误的类。不是所有的错误Exception都能获取到的,虚拟机报错Exception就获取不到,必须用Error获取。

体系上的优化,分为 结构优化,日志优化,可读性优化,异常优化

18.结构优化:

A. action层尽量不要做参数的校验和逻辑书写,它只负责请求的转发和响应,入参和出参

 

B. Service层逻辑要清晰,尽量不要有if,for的出现,全部封装到公共方法去调用

 

C. DAO层只提供持久层相关操作,如封装参数进map供持久层使用,尽量不要有逻辑在里面,所有的逻辑应都在service里完成

19.日志优化:

A. 方法开始后、结束前书写日志

 

B. 抓取异常时书写日志

 

C. 特殊情况时书写。如需要提前return时

20.可读性优化:

A. 类、方法必须要有注释

 

B. 在一些比较大的逻辑前加上注释

 

C. 一个完美的service层,应逻辑清晰,一行代码代表一个逻辑,通篇下来可读性非常强

21.异常优化:

A. 异常应只用来进行错误处理,而不是逻辑处理(异常也是高开销的操作)

 

B. 善用多种异常,但是在service层应只有一个 try cath来抓取多个异常,并分别处理

 

C. 异常理应在service层全部处理完,不能再继续往上抛(理论上可以接续抛,但service本来就是处理逻辑的,尽量在本层处理完)

 

 

 

                            ---------------长按二维码关注程序媛小姐姐公众号有更多彩蛋哦---------------

                                            

你可能感兴趣的:(javaSE)