首页 > 代码库 > 代码优化

代码优化

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.

 

 

 

18、及时清除不再需要的会话

 

为了清除不再活动的会话,许多应用服务器都有默认的会话超时时间,一般为30分钟。当应用服务器需要保存更多的会话时,如果内存不足,那么操作系统会把部分数据转移到磁盘,应用服务器也可能根据MRU(最近最频繁使用)算法把部分不活跃的会话转储到磁盘,甚至可能抛出内存不足的异常。如果会话要被转储到磁盘,那么必须要先被序列化,在大规模集群中,对对象进行序列化的代价是很昂贵的。因此,当会话不再需要时,应当及时调用HttpSession的invalidate()方法清除会话。

 

19、实现RandomAccess接口的集合比如ArrayList,应当使用最普通的for循环而不是foreach循环来遍历

 

这是JDK推荐给用户的。JDK API对于RandomAccess接口的解释是:实现RandomAccess接口用来表明其支持快速随机访问,此接口的主要目的是允许一般的算法更改其行为,从而将其应用到随机或连续访问列表时能提供良好的性能。实际经验表明,实现RandomAccess接口的类实例,假如是随机访问的,使用普通for循环效率将高于使用foreach循环;反过来,如果是顺序访问的,则使用Iterator会效率更高。可以使用类似如下的代码作判断:

 

if (list instanceof RandomAccess)
{
    for (int i = 0; i < list.size(); i++){}
}
else
{
    Iterator<?> iterator = list.iterable();
    while (iterator.hasNext()){iterator.next()}
}

 

foreach循环的底层实现原理就是迭代器Iterator,参见Java语法糖1:可变长度参数以及foreach循环原理。所以后半句"反过来,如果是顺序访问的,则使用Iterator会效率更高"的意思就是顺序访问的那些类实例,使用foreach循环去遍历。

 

 

 

20、使用同步代码块替代同步方法

 

这点在多线程模块中的synchronized锁方法块一文中已经讲得很清楚了,除非能确定一整个方法都是需要进行同步的,否则尽量使用同步代码块,避免对那些不需要进行同步的代码也进行了同步,影响了代码执行效率。

 

 

 

21、将常量声明为static final,并以大写命名

 

这样在编译期间就可以把这些内容放入常量池中,避免运行期间计算生成常量的值。另外,将常量的名字以大写命名也可以方便区分出常量与变量

 

 

 

22、不要创建一些不使用的对象,不要导入一些不使用的类

 

这毫无意义,如果代码中出现"The value of the local variable i is not used"、"The import java.util is never used",那么请删除这些无用的内容

 

 

 

23、程序运行过程中避免使用反射

 

关于,请参见反射。反射是Java提供给用户一个很强大的功能,功能强大往往意味着效率不高。不建议在程序运行过程中使用尤其是频繁使用反射机制,特别是Method的invoke方法,如果确实有必要,一种建议性的做法是将那些需要通过反射加载的类在项目启动的时候通过反射实例化出一个对象并放入内存----用户只关心和对端交互的时候获取最快的响应速度,并不关心对端的项目启动花多久时间。

 

 

 

24、使用数据库连接池和线程池

 

这两个池都是用于重用对象的,前者可以避免频繁地打开和关闭连接,后者可以避免频繁地创建和销毁线程

 

 

 

25、使用带缓冲的输入输出流进行IO操作

 

带缓冲的输入输出流,即BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,这可以极大地提升IO效率

 

代码优化