注:本文中使用JDK1.6版本。

        Java从一开始就提供了丰富的类库,这也是其受到广泛使用的一个重要原因。一般来说,类库中的方法经过多年的实践,也的确有很多值得学习的地方,但是针对具体的应用而言,类库的方法真的是最优的吗?


        以String为例,String是Java中最重要的几个类之一,提供了数十个方法,其中的一个格式化方法是:


public static String format(String format, Object ... args)

        此方法提供了丰富的使用方法,如格式化为指定进制的数据,千分位分隔等,以及我们最常用的占位符替换的方法:

String.format(“This is my %s”, “house”);

       正因为format方法提供了丰富的功能,使得其牺牲了一些性能上的要求,在一些要求极致性能且需求较为简单的地方就并不适合直接使用。下面的例子将通过比较自定义的format方法和类库中的format方法来对二者的性能作一个对比:


 

/**
 *===============================================================
 * @author:       jiehao
 * @date:         2016年6月5日 上午11:48:51
 *===============================================================
 * 修订日期                                                         修订人                                                    描述
 */
package com.zjh.importnew.articles;
 
import org.junit.Test;
 
/**
 * <p>测试String的类库方法和自己简单实现方法的性能差异 
 * @author jiehao
 * @date   2016年6月5日 上午11:48:51
 * @see 
 * @since   V1.0 
 * @modified TODO
 */
public class StringTest {
/**
 * <p>自定义format方法
 * <p>仅针对%s这种占位符作替换
 * @param strSource 原始字符串
 * @param strFrom 待替换的不定字符数组
 * @return 替换后的字符串
 * @author jiehao
 * @date   2016年6月5日 上午11:50:11
 * @since   V1.0
 * @see   
 * @modified TODO
 */
public static String format(String strSource, String... strFrom) {
  if (strSource == null || strFrom == null) {
      return strSource;
   }
  int i = 0;<span style="font-family: Arial, Helvetica, sans-serif;">  </span>
  StringBuffer buffer = new StringBuffer();
  int k=0;
  while ((i = strSource.indexOf("%s")) >= 0) {
    buffer.append(strSource.substring(0, i));
    buffer.append(strFrom[k++]);
    strSource = strSource.substring(i + 2, strSource.length());
  }
  buffer.append(strSource);
  return buffer.toString();
}
/**
 * <p>单元测试
 * <p>由于机器、环境、编译优化等差异,测试效果略有差异
 * @author jiehao
 * @date   2016年6月5日 上午11:58:19
 * @since   V1.0
 * @see   
 * @modified TODO
 */
@Test
public void testCompareFormat(){
  String source = "StringTest replace 1st value= %s, 2nd value = %s.";
  String firstValue = "testCompareFormat1";
  String secondValue = "testCompareFormat2";
  int loopNum = 1000000;
  long startTime1 = System.currentTimeMillis();
  String afterLib = null;
  for (int i = 0; i < loopNum; i++) {
    afterLib = String.format(source, firstValue, secondValue);
  }
  long endTime1 = System.currentTimeMillis();
  System.out.println("source = " + source + ", after format in lib = " + afterLib + ", time = " + (endTime1 - startTime1) + "ms");
 
  long startTime2 = System.currentTimeMillis();
  String afterMySelf = null;
  for (int i = 0; i < loopNum; i++) {
    afterMySelf = format(source, firstValue, secondValue);
  }
  long endTime2 = System.currentTimeMillis();
  System.out.println("source = " + source + ", after format in myself = " + afterMySelf + ", time = " + (endTime2 - startTime2) + "ms");

}
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

        测试结果表明:如果只是要求替换字符串中的”%s”占位符这种应用,自定义的接口方法甚至比format快上五六倍以上。笔者曾经的系统中就遇到过每天数十亿级的替换,每天累积下来的时间并不少,此时用自带的String.format方法显然并非最优方案。另一方面,为了实现类库中format丰富的功能,其内部是由一个复杂的正则表达式去匹配的,在并发时会大量消耗CPU资源,对服务器性能造成一定的影响。


      小结一下:


      1、Java某些类库(包括一些广泛应用的第三方jar)并非十全十美,如广受诟病的Date和Calander(好消息是,这两个类在JDK1.8中终于重新实现了),所以针对高性能的的场景,不要过度迷信类库的方法,类库方法未必是最优方案,需要具体问题具体解决。


      2、但在绝大多数情况下,类库方法都更加灵活和强大,依然是我们的首选。这种首选不仅仅体现在性能(大部分类库方法的性能都很好)和使用范围上,而且能减少项目的维护成本,享受版本更替时类库无形之间带来的改进。正如Joshua Bloch在《Effective Java》中指出的那样需要“谨慎地进行优化”,除非能带来明确地提升,否则类库依然是第一选择。