String, StringBuffer и StringBuilder: сравнение

Многие думают, что конкатенация строк происходит быстрее всего в классе String с использованием сложения (т.е. операторов + или +=). Сравним быстродействие классов String, StringBuffer и StringBuilder в Java.
public class One {
    public static void main(String[] args) {
        String string = new String("My string test");
        string += " for String class";
    }
}
public class Two {
    public static void main(String[] args) {
        StringBuffer string = new StringBuffer("My string test");
        string.append(" for String class");
    }
}
public class StrBuild {
    public static void main(String[] args) {
        StringBuilder string = new StringBuilder("My string test");
        string.append(" for String class");
    }
}

1 Сравнение байт-кода


Сравниваем байт-код с помощью
javap -c NameOfClass.class
В результате получаем следующий вывод на экран:
Compiled from "One.java"
public class Strings.One {
  public Strings.One();
    Code:
       0: aload_0       
       1: invokespecial #8                  // Method java/lang/Object."":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: new           #16                 // class java/lang/String
       3: dup           
       4: ldc           #18                 // String My string test
       6: invokespecial #20                 // Method java/lang/String."":(Ljava/lang/String;)V
       9: astore_1      
      10: new           #23                 // class java/lang/StringBuilder
      13: dup           
      14: aload_1       
      15: invokestatic  #25                 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
      18: invokespecial #29                 // Method java/lang/StringBuilder."":(Ljava/lang/String;)V
      21: ldc           #30                 // String  for String class
      23: invokevirtual #32                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      26: invokevirtual #36                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      29: astore_1      
      30: return        
}
Compiled from "Two.java"
public class Strings.Two {
  public Strings.Two();
    Code:
       0: aload_0       
       1: invokespecial #8                  // Method java/lang/Object."":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: new           #16                 // class java/lang/StringBuffer
       3: dup           
       4: ldc           #18                 // String My string test
       6: invokespecial #20                 // Method java/lang/StringBuffer."":(Ljava/lang/String;)V
       9: astore_1      
      10: aload_1       
      11: ldc           #23                 // String  for String class
      13: invokevirtual #25                 // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
      16: pop           
      17: return        
}
Compiled from "StrBuild.java"
public class Strings.StrBuild {
  public Strings.StrBuild();
    Code:
       0: aload_0       
       1: invokespecial #8                  // Method java/lang/Object."":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: new           #16                 // class java/lang/StringBuilder
       3: dup           
       4: ldc           #18                 // String My string test
       6: invokespecial #20                 // Method java/lang/StringBuilder."":(Ljava/lang/String;)V
       9: astore_1      
      10: aload_1       
      11: ldc           #23                 // String  for String class
      13: invokevirtual #25                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      16: pop           
      17: return        
}
Здесь видно, что байт-код StringBuffer и StringBuilder оказался почти в два раза короче, чем для String.

2 Время выполнения


Для оценки быстродействия двух классов был использован следующий алгоритм:
public class Three {
    public static String concatWithString() {
        String t = "Cat";
        for (int i = 0; i < 100000; i++) {
            t += "Dog";
        }
        return t;
    }

    public static String concatWithStringBuffer() {
        StringBuffer sb = new StringBuffer("Cat");
        for (int i = 0; i < 100000; i++) {
            sb.append("Dog");
        }
        return sb.toString();
    }

    public static String concatWithStringBuilder() {
        StringBuilder sb = new StringBuilder("Cat");
        for (int i = 0; i < 100000; i++) {
            sb.append("Dog");
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        concatWithString();
        System.out.println("Concat with String took: " + (System.currentTimeMillis() - start) + "ms");
        start = System.currentTimeMillis();
        concatWithStringBuffer();
        System.out.println("Concat with StringBuffer took: " + (System.currentTimeMillis() - start) + "ms");
        start = System.currentTimeMillis();
        concatWithStringBuilder();
        System.out.println("Concat with StringBuilder took: " + (System.currentTimeMillis() - start) + "ms");
    }
}
В результате я получил следующие значения:
Concat with String took: 12478ms
Concat with StringBuffer took: 6ms
Concat with StringBuilder took: 4ms
Используя полученные результаты и документацию можно сделать следующие выводы
1) String является неизменяемым объектом (immutable), в то время как StringBuffer и StringBuilder являются изменяемыми объектами (mutable).
2) Используйте String вам требуется неизменяемый объект, Stringbuffer - если требуется изменяемый и потокобезопасность, StringBuilder изменяемый и не требуется обеспечивать безопасность потоков.

Комментариев нет:

Отправить комментарий