String拼接字符串效率低,你知道原因吗?

为什么String用"+"拼接字符串效率低下,最好能从JVM角度谈谈吗?
对于这个问题,我们先来看看如下代码:

public class StringTest {
  public static void main(String[] args) {
  String a = "abc";
  String b = "def";
  String c = a + b;
  String d = "abc" + "def";
  System.out.Println(c);
  System.out.Println(d);
  }
}

打印结果:

abcdef
abcdef

从上面代码示例中,我们看到两种方式拼接的字符串打印的结果是一样的。但这只是表面上的,实际内部运行不一样。

两者究竟有什么不一样?
String c = a + b; "+"相当于new了一个StringBuilder,然后调用StringBuilder的初始化方法,然后进行append操作,最后toString();
String d = “abc” + “def”; 两个常量在同行发生时,JVM在编译时就认为这个“+”是没有用处的,编译时直接变成String d = “abcdef”;

那么效率问题从何说起?
其实上面两个例子,连接字符串行表达式很简单,那么"+"和StringBuilder基本是一样的,但如果结构比较复杂,如使用循环来连接字符串,那么产生的Java Byte Code就会有很大的区别。我们再来看看下面一段代码:

import java.util.*;
public class StringTest {
     public static void main(String[] args){
          String s = "";
          Random rand = new Random();
         for (int i = 0; i < 10; i++){
              s = s + rand.nextInt(1000) + " ";
          }
          System.out.println(s);
      }
}

由上可知,“+”在for循环内部,所以每次执行就会创建一个StringBuilder,虽然Java有垃圾回收器,但是回收器的工作时间不固定,如果不断产生垃圾,会占用大量的资源。所以应该在程序中直接使用StringBuilder来连接字符串,如下:

import java.util.Random;
public class StringTest {
    public static void main(String[] args) {
        Random rand = new Random();
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < 10; i++) {
            result.append(rand.nextInt(1000));
            result.append(" ");
        }
        System.out.println(result.toString());
    }
}

从上面的反编译结果可以看出,创建StringBuilder的代码被放在了for语句外。虽然这样处理在源程序中看起来复杂,但却换来了更高的效率,同时消耗的资源也更少了。

所以,从上述几个例子中我们得出的结论是:String采用连接运算符(+)效率低下,都是上述循环、大批量数据情况造成的,每做一次"+"就产生个StringBuilder对象,然后append后就扔掉。下次循环再到达时重新产生个StringBuilder对象,然后append字符串,如此循环直至结束。如果我们直接采用StringBuilder对象进行append的话,我们可以节省创建和销毁对象的时间。如果只是简单的字面量拼接或者很少的字符串拼接,性能都是差不多的。

你可能感兴趣的:(#,String)