# 常用代码优化方法

  • 尽量重用对象,不要循环创建对象

    比如:for 循环字符串拼接

  • 容器类初始化的时候指定长度

    List<String> collection = new ArrayList<String>(5);
    Map<String,String> map = new HashMap<String,String>(32);
    
    1
    2

    版本不同源码的实现不同,JDK8 中,对于 ArrayList 来说,如果不指定初始容量大小,那么则是 0,添加第一个就会触发数组扩容(保存数据使用的是一个 Object 数组 )

  • ArrayList 随机遍历快,LinkedList 添加快删除快

  • 集合遍历尽量减少重复计算

    比如下面这个,将集合的大小用变量 len 存储起来

     for (int i = 0,len = collection.size(); i < len; i++) {
                
     }
    
    1
    2
    3

    但是这个从源码中来看,直接返回的常量,看不出什么来。字节码层面笔者太弱,看不太懂。

  • 使用 Entry 遍历 Map

    for(Map.Entry<String,String> entry: map.entrySet()){
      String key = entry.getKey();
      String value = entry.getValue();
    }
    
    1
    2
    3
    4
  • 大数组复制用 System.arraycopy

    底层使用了 c 代码来实现

  • 尽量使用基本类型而不是包装类型

    Integer i = 100;
    System.out.println(i);
    
    1
    2

    比如上述代码,它做了一个自动装箱的操作,从字节码中可以看出来使用了 Integer.valueOf 函数进行装箱

             0: bipush        100
             2: invokestatic  #16                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
             5: astore_0
    
    1
    2
    3
  • 不要手动调用 System.gc()

    前面讲过了对生产环境进行 GC 调优会禁用该代码,写了也不起作用,还有一个原因是,这个方法只是你通知需要进行 GC 操作,但是什么时候执行是不确定的。

  • 及时消除过期对象的引用,防止内存泄露

  • 尽量使用非同步的容器

    如 Vector VS ArrayList

    Vector 中几乎所有的操作都加锁了,有读写操作的时候,导致读都是串行的,性能很低

  • 尽量减少同步作用范围

    synchronized 方法 VS 代码块

  • ThreadLocal 缓存线程不安全的对象

    比如:SimpleDateFormat,它的构造成本较大,而且不是线程安全的,就可以使用 ThreadLocal 缓存起来,在同一个线程中时同一个对象操作(因为同一个线程中没有并发问题,就不会导致使用上的线程安全问题)

  • 尽量使用延迟加载

  • 尽量减少使用反射,如果必须要用可以考虑加缓存

  • 尽量使用连接池、线程池、对象池、缓存

  • 及时释放资源

    如 I/O 流、Socket、数据库链接

  • 慎用异常,不要用抛异常来表示正常的业务逻辑

    因为在异常的时候,会将整个堆栈记录下来,这会比较耗时

  • String 操作尽量少用正则表达式

  • 日志输出注意使用不同的级别

  • 日志中参数拼接使用占位符,不要使用 + 号拼接

    log.info( "ooxx:" + orderId);  // 不推荐
    log.info( "ooxx:{}", orderId ); // 推荐
    
    1
    2

    当你不打印 info 日志级别的时候,使用 + 号拼接的时候也会执行拼接操作,而第二种则不会。