java字符串执行效率详解

2011年09月25日 08:24 来源:互联网 | 关键词:java 字符串 执行 效率 详解 比较

  比较JAVA中String ,StringBuffer,SrtingBuilder三个对象连接字符串的效率。

  我们经常都听有经验的人说,避免使用String通过“+”连接字符串,特

  别是连接的次数很多的时候,一定要用StringBuffer。

  比较下究竟谁的效率高,下边是测试代码,可直接运行:

  package com.kj.map;

  public class TestStringPerformance {

  

   public static final int n =2000;

  

  

   public static void main(String[] args){

  

   TestStringPerformance.testStringTime();

   TestStringPerformance.testStringBufferTime();

   TestStringPerformance.testStringBuilderTime();

   }

  

   /**

   * 测试String连接字符串

   */

   public static void testStringTime(){

  

   long startTime=System.currentTimeMillis();

  

   String str="";

  

   for(int i=0;i

  

   str+="_"+i;

  

   }

  

   long endTime=System.currentTimeMillis();

  

   long result=endTime-startTime;

   //System.out.println(str);

   System.out.println("String time:"+result);

   }

  

   /**

   * 测试连接StringBuffer

   */

   public static void testStringBufferTime(){

  

   long startTime=System.currentTimeMillis();

  

   for(int i=0;i

  

   StringBuffer sb=new StringBuffer();

   sb.append("_"+n);

  

   }

  

   long endTime=System.currentTimeMillis();

  

   long result=endTime-startTime;

   System.out.println("StringBuffer time is:"+result);

  

   }

   /**

   * 测试连接StringBuilder

   */

   public static void testStringBuilderTime(){

  

   long startTime=System.currentTimeMillis();

  

   for(int i=0;i

  

   StringBuilder sb=new StringBuilder();

   sb.append("_"+i);

   }

  

   long endTime=System.currentTimeMillis();

  

   long result=endTime-startTime;

   System.out.println("StringBuilder time:"+result );

  

   }

  

  }

  分别测试了n=10,100,500,1000,5000,10000,20000的时候,三个对象连接字符串所花费的时间,

  做了个简单统计,得到如下数据:

  连接次数(n) 所需时间(单位毫秒)

  String StringBuffer StringBuilder

  10 0 0 0

  100 0 0 0

  500 31 16 0

  1000 63 31 16

  5000 781 63 47

  10000 7547 63 62

  20000 62984 94 63

  由上边的图表结果对比,可以清楚的看出,为什么大家都鼓励用StringBuffer连接字符串了。在连接次数少

  的情况下,String的低效率表现并不是很突出,但是一旦连接次数多的时候,性能影响是很大的,String进

  行2万次字符串的连接,大约需要1分钟时间,而StringBuffer只需要94毫秒,相差接近500倍以上。而

  StringBuffer和StringBuilder差别并不大,StringBuilder比StringBuffer稍微快点,我想是因为StringBuffer

  是线程序安全的,StringBuilder不是线程序安全的,所以StringBuffer稍微慢点。

  但是为什么String如此慢呢,分析以下代码

  String result="";

  result+="ok";

  这段代码性能很低,原因是java中的String类不可变的(immutable),

  通过使用javap工具我们可以知道其实上面的代码在编译成字节码的时候等同的源代码是:

  String result="";

  StringBuffer temp=new StringBuffer();

  temp.append(result);

  temp.append("ok");

  result=temp.toString();

  短短的两个语句怎么呢变成这么多呢?问题的原因就在String类的不可变性上。

  所以,如果你对字符串中的内容经常进行操作,特别是内容要修改时,那么使用StringBuffer,如果最后

  需要String,那么使用StringBuffer的toString()方法好了。但是 StringBuilder 的实例用于多个线程是不安

  全的。如果需要这样的同步,则建议使用 StringBuffer,因为StringBuffer是线程安全的。在大多数非多

  线程的开发中,为了提高效率,可以采用StringBuilder代替StringBuffer,速度更快。

  补1:

  public static String concat1(String s1, String s2, String s3, String s4, String s5, String s6) {

  String result = "";

  result += s1;

  result += s2;

  result += s3;

  result += s4;

  result += s5;

  result += s6;

  return result;

  }

  public static String concat2(String s1, String s2, String s3, String s4, String s5, String s6) {

  StringBuffer result = new StringBuffer();

  result.append(s1);

  result.append(s2);

  result.append(s3);

  result.append(s4);

  result.append(s5);

  result.append(s6);

  return result.toString();

  }

  public static String concat3(String s1, String s2, String s3, String s4, String s5, String s6) {

  return new StringBuffer(s1.length() + s2.length() + s3.length() + s4.length() + s5.length() + s6.length())

  .append(s1).append(s2).append(s3).append(s4).append(s5).append(s6).toString();

  }

  public static String concat4(String s1, String s2, String s3, String s4, String s5, String s6) {

  return s1 + s2 + s3 + s4 + s5 + s6;

  }

  public static String concat5(String s1, String s2, String s3, String s4, String s5, String s6) {

  return new StringBuilder(s1.length() + s2.length() + s3.length() + s4.length() + s5.length() + s6.length())

  .append(s1).append(s2).append(s3).append(s4).append(s5).append(s6).toString();

  }

  第一种写法是最土的写法,也最累赘,事实上看到这样的代码我都会有点头疼。

  看过《Effective Java》的朋友都知道用StringBuffer吧,用第二种写法的人应该也不少。

  第4种写法当然最简捷,最优美的了,就是不知道性能怎么样。

  Java 5里加了个StringBuilder类,与StringBuffer功能一样,就是没有同步,

  所有用StringBuilder代替StringBuffer肯定对性能有好处,这样就产生的第5种写法。

  还是做个测试有说服力。我的机器上同时装了JDK 5和JDK 6,两个都测了一下。

  执行每个函数10000000次(输入的每个参数都是"a"),各种写法用时如下,单位毫秒:

  JDK 5:

  concat1: 13776

  concat2: 5081

  concat3: 4944

  concat4: 4202

  concat5: 4047

  JDK 6:

  concat1: 11801

  concat2: 3930

  concat3: 3976

  concat4: 3353

  concat5: 3440

  可以看出第1种写法果然最慢,第二种写法由于用了StringBuffer,快了很多。

  奇怪的是第4种写法竟然也很快,比用StringBuffer还快,怎么回事?

  其实如果你调试过字符串连接的执行过程就会知道当用第4种写法时Java会自动使用StringBuilder.append()函数来进行连接。

  所以最简捷的第4种写法已经够快了。

  在JDK 5里,第5种写法最快,因为在创建StringBuilder的时候预先计算了总长度,消除了内存重分配。

  不过没有必要这么写,JDK 6里已经为第4种写法做了更好的优化,第5种写法反而慢了。

  

关键字:java 字符串 执行 效率 详解 比较 | 来源:互联网 | 责任编辑:系统管理员 | 最后编辑:2011年09月25日 08时30分30秒

Copyright©2010 -普索网CMS2.0 All Rights Reserved 版权所有
京ICP备09081852号