前言之前分享过一篇关于代码优化的文章:条件语句的多层嵌套问题优化,帮你写出不让同事吐槽的代码!今天再次分享一些日常工作中常用的代码优化技巧。帮助大家!最小化文本类成员和方法的可见性。例子:如果是私有方法,想删就删。如果是公共服务方法,或者公共成员变量,不用想太多就删掉。用移位运算代替乘除法计算机使用二进制表示,移位运算可以大大提高性能。<<左移相当于乘以2;>>>右移相当于除以2;>>>无符号右移相当于除以2,但忽略符号位,空位补0。a=val<<3;b=val>>1;尽量减少变量的重复计数我们知道调用方法是有消耗的,包括创建栈帧,调用方法时保护场景,还原场景等//反例for(inti=0;ilist,intindex){try{returnlist.get(index);}catch(IndexOutOfBoundsExceptionex){returnnull;}}//正例publicStringtest2(Listlist,intindex){if(index>=list.size()||index<0){returnnull;}returnlist.get(index);}使用局部变量避免在堆上分配由于堆资源是多线程共享的,是垃圾的主要存放区域收藏家作品。对象过多会造成GC压力,可以通过局部变量在栈上分配变量。这样变量会随着方法的执行而销毁,可以减轻GC的压力。缩小变量的范围注意变量的范围,尽量减少对象的创建。如下代码,每次进入方法都会创建变量s,可以在if语句内部移动。publicvoidtest(Stringstr){finalints=100;if(!StringUtils.isEmpty(str)){intresult=s*s;}}尝试采用懒加载策略,只在需要时创建Stringstr="MoonwithFlyingFish";if(name==“公众号”){list.add(str);}if(name==“公众号”){Stringstr="MonowithFlyingFish";list.add(str);}访问静态variables直接使用类名来使用对象来访问静态变量。此方法需要额外的寻址操作。需要先找到变量对应的类,再找到类对应的变量。//反例nti=objectA.staticMethod();//正例nti=ClassA.staticMethod();使用StringBuilder进行字符串拼接,使用StringBuilder或者StringBuffer,不要使用+号。//反例publicclassStringTest{@TestpublicvoidtestStringPlus(){Stringstr="111";str+="222";str+="333";System.out.println(str);}}//正例publicclassTestMain{publicstaticvoidmain(String[]args){StringBuildersb=newStringBuilder("111");sb.append("222");sb.append(333);System.out.println(sb.toString());}}重写对象的HashCode,不要简单的返回一个固定值有些同学在开发重写HashCode和Equals方法的时候,会把HashCode的值返回一个固定值0,这是不合适的。当这些对象存储在HashMap中时,性能会很低,因为HashMap的Hash槽是由HashCode定位的。当有冲突时,会使用链表或者红黑树来组织节点,固定返回0,相当于使Hash寻址功能失效。HashMap等集合在初始化时,有很多对象指定了初始值的大小,比如ArrayList、StringBuilder等,通过指定初始值的大小,可以减少扩容带来的性能损失。初值的计算可以参考《阿里巴巴开发手册》:不要一直在循环中创建对象引用//反例for(inti=1;i<=size;i++){Objectobj=newObject();}//正例Objectobj=null;for(inti=0;i<=size;i++){obj=newObject();}第一种会导致内存中存在sizeObject对象引用。如果大小很大,会消耗内存。遍历Map时,使用EntrySet方法使用EntrySet方法,可以直接返回set对象,可以直接使用;而使用KeySet方法,获取的是key集合,需要再进行一次get操作,需要多一个操作步骤,所以更推荐使用EntrySet方法遍历Map。Set>entryseSet=nmap.entrySet();for(Map.Entryentry:entryseSet){System.out.println(entry.getKey()+","+entry.getValue());}多线程下不要使用RandomRandom类的同一个seed。在并发访问的情况下会发生竞争,导致性能下降。建议在多线程环境下使用ThreadLocalRandom类。publicstaticvoidmain(String[]args){ThreadLocalRandomthreadLocalRandom=ThreadLocalRandom.current();Threadthread1=newThread(()->{for(inti=0;i<10;i++){System.out.println("Thread1:"+threadLocalRandom.nextInt(10));}});Threadthread2=newThread(()->{for(inti=0;i<10;i++){System.out.println("Thread2:"+threadLocalRandom.nextInt(10));}});thread1.start();thread2.start();}推荐使用LongAddr自增。自增操作可以通过synchronized和volatile的结合来控制线程安全,也可以使用原子类(比如AtomicLong)。后者的速度高于前者。AtomicLong使用CAS进行比较和替换,在线程多的时候会造成无效自旋过多。LongAdder可用于替代AtomicLong以进一步提高性能。publicclassTest{publicintlongAdderTest(Blackholeblackhole)throwsInterruptedException{LongAdderlongAdder=newLongAdder();for(inti=0;i<1024;i++){longAdder.add(1);}returnlongAdder.intValue();}}程序应该少用反射了的功能很强大,但是是通过解析字节码实现的,性能不是很理想。现实中,有很多方法可以优化反射,比如缓存反射执行的过程(比如Method),使用多路复用来加速反射。Java7.0之后,新增了一个包java.lang.invoke,新增了一条JVM字节码指令invokedynamic,支持从JVM层面直接通过字符串调用目标方法。