1.尽量用final修饰类和方法
final修饰的类不可以继承,final修饰的方法不可以被重写。指定了一个类是final的,那么它里面所有方法都是final的(不可以继承也就不存在重写)。java编译器会寻找机会内联所有final方法,内联可以提升效率。
2.尽量重用对象
对于String对象的使用,字符串链接时应该使用StringBuilder/StringBuffer代替。
3.尽可能使用局部变量
因为局部变量保持在栈中,速度快,而且方法结束后就没有了。
4.及时关闭流
io操作要及时关闭以释放资源,不然这些大对象会有很大的开销,会有严重的后果。
5.尽量减少对变量的重复计算
比如计算集合或者数组的数量/长度时,不要在循环体中不停的计算数量/长度。
6.尽可能使用懒加载
比如
String str = "aaa"; if (i == 1) { list.add(str); }
应该改为
if (i == 1) { String str = "aaa"; list.add(str); }
7.慎用异常
异常对性能不利。只能用于错误处理,不应该用于控制流程。
8.如果能估计到内容长度,最好自己给底层以数组方式实现的集合,工具类指定初始长度。
比如StringBuilder,默认的是16个字符的空间,当达到最大容量时,会把自身容量扩展到当前2倍并加2。只要它到达最大容量,那么它就必须创建一个新的字符数组,并把旧的字符数组内容拷贝新字符数组中去(非常的费时间,并且浪费资源)。
对于hashmap这种数组+链表的集合,因为一个table上只链接一个对象的可能性几乎为0,所以,初始大学最好指定为2的n次幂。比如估计有2000个元素,设置为new HashMap(128)或者为new HashMap(256)都可以
9.当复制大量数据的时候使用,System.arraycopy();
10.乘法和除法使用位操作
一个数x左移n位置相当于x乘以2的n次方。比如 x*8 等于 x<<3
一个数x右移n位置相当于x除以2的n次方。比如x/8 等于 x>>3
11.循环内不要重复创建对象的引用
for (int i = 1; i <= count; i++) { Object obj = new Object(); }
要改为
Object obj = null; for (int i = 0; i <= count; i++) { obj = new Object(); }
这样可以节约内存。
12.如果没有线程安全需要,尽量使用hashmap,arraylist,stringbuider。因为hashtable,vector,stringbuffer性能开销很大。
13.在合适的场合使用单例
使用单例可以减轻加载的负担,缩短加载时间,提供加载效率。
(1)控制资源的使用,通过线程同步来控制资源的并发访问
(2)控制实例的产生,以达到节约资源的目的
(3)控制数据的共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信
14.避免适用静态变量
如果某个对象被静态变量应用,gc通常不会回收该堆内存。
public class A { private static B b = new B(); }
此时b的生命周期和A相同,只要A没有卸载,那么b一直能指向对象B,根据可达性分析,对象一直不会回收,直到A卸载。
15.及时清除不需要的会话
为了清除不再活动的会话,许多应用服务器都有默认的会话超过时间,一般为30分钟。当应用服务器需要保存更多会话时,如果内存不足,那么操作系统会把部分数据转移到磁盘,应用服务器也可能根据mru(最近最频繁使用)算法把部分不活跃的会话转储到磁盘。如果会话转储到
磁盘,需要序列化,在大规模集群中,对对象进行序列化是很昂贵的。因此,如果当前会话不需要时,应该调用httpSession的invalidate方法清除会话。
16.实现RandomAccess接口的集合,应该用普通的for循环而不是foreach。比如arraylist
实现RandomAccess接口用来表明其支持快速随机访问,使用普通的for循环效率高,如果是顺序访问(没有实现这个接口),那么用foreach会比较快。
17.使用同步代码块代替同步方法
尽量使用同步代码块,避免对那些不需要同步的代码进行同步,从而影响代码效率。
18.把常量声明为static final,以大写命名
19.不要创建不使用的对象,不要导入不使用的类
20.程序中避免使用反射
反射功能强大,但是功能强大往往是效率不高,不建议使用反射,特别是method的invoke方法。如果实在有必要,建议把那些需要通过反射加载的类在项目启动时通过反射实例化一个对象并放入内存中。
21.使用数据库连接池和线程池
用于重用对象,前者是避免频繁的打开和关闭连接,后者是避免频繁创建和销毁线程。
22.使用带缓冲的输入输出流进行io操作
带缓冲的输入输出流,即BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,这可以极大地提升IO效率。
23.随机访问较多的场景用Arraylist,元素删除较多的场景用LinkedList
24.不要让public方法中有太多的形参
违反了面向对象的思想,形参多容易错。
25.字符串变量和字符串常量的equals的时候,把字符串常量写前面。
String str = "123"; if (str.equals("123")) { ... }
改为
String str = "123"; if ("123".equals(str)) { ... }
这样可以避免出现空指针错。
26.不要对超出范围的基本数据类型做向下强制转型
public static void main(String[] args) { long l = 12345678901234L; int i = (int)l; System.out.println(i); }
结果
1942892530
Java中long是8个字节64位的,所以12345678901234在计算机中的表示应该是:
0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010
一个int型数据是4个字节32位的,从低位取出上面这串二进制数据的前32位是:
0111 0011 1100 1110 0010 1111 1111 0010
27.把基本数据类型转为字符串,基本数据类型toString方法是最快的,其次String.valueOf次之,数据+“”最慢。