StringBuilder срещу StringBuffer в Java

1. Общ преглед

В тази кратка статия ще разгледаме приликите и разликите между StringBuilder и StringBuffer в Java.

Просто казано, StringBuilder беше въведен в Java 1.5 като заместител на StringBuffer .

2. Прилики

И StringBuilder, и StringBuffer създават обекти, които съдържат променлива последователност от символи. Нека да видим как работи това и как се сравнява с неизменяем клас String :

String immutable = "abc"; immutable = immutable + "def";

Въпреки че може да изглежда, че модифицираме един и същ обект, като добавяме „def“ , ние създаваме нов, тъй като екземплярите на String не могат да бъдат модифицирани.

Когато използваме StringBuffer или StringBuilder, можем да използваме метода append () :

StringBuffer sb = new StringBuffer("abc"); sb.append("def");

В този случай не е създаден нов обект. Ние нарекохме добавяне () метода на SB инстанция и модифициран неговото съдържание. StringBuffer и StringBuilder са променливи обекти.

3. Разлики

StringBuffer е синхронизиран и следователно безопасен за нишки. StringBuilder е съвместим със StringBuffer API, но без гаранция за синхронизация.

Тъй като това не е безопасно за нишки изпълнение, то е по-бързо и се препоръчва да се използва на места, където няма нужда от безопасност на нишките.

3.1. производителност

При малки повторения разликата в производителността е незначителна. Нека направим бърз микро-бенчмарк с JMH:

@State(Scope.Benchmark) public static class MyState { int iterations = 1000; String initial = "abc"; String suffix = "def"; } @Benchmark public StringBuffer benchmarkStringBuffer(MyState state) { StringBuffer stringBuffer = new StringBuffer(state.initial); for (int i = 0; i < state.iterations; i++) { stringBuffer.append(state.suffix); } return stringBuffer; } @Benchmark public StringBuilder benchmarkStringBuilder(MyState state) { StringBuilder stringBuilder = new StringBuilder(state.initial); for (int i = 0; i < state.iterations; i++) { stringBuilder.append(state.suffix); } return stringBuilder; }

Използвахме стандартния режим на пропускателна способност - т.е. операции за единица време (по-висок резултат е по-добър), който дава:

Benchmark Mode Cnt Score Error Units StringBufferStringBuilder.benchmarkStringBuffer thrpt 200 86169.834 ± 972.477 ops/s StringBufferStringBuilder.benchmarkStringBuilder thrpt 200 91076.952 ± 2818.028 ops/s

Ако увеличим броя на итерациите от 1k на 1m, ще получим:

Benchmark Mode Cnt Score Error Units StringBufferStringBuilder.benchmarkStringBuffer thrpt 200 77.178 ± 0.898 ops/s StringBufferStringBuilder.benchmarkStringBuilder thrpt 200 85.769 ± 1.966 ops/s

Нека обаче имаме предвид, че това е микро-бенчмарк, който може или не може да има реално въздействие върху действителното, реално изпълнение на приложението.

4. Заключения

Най-просто казано, StringBuffer е безопасно изпълнение с нишки и следователно по-бавно от StringBuilder .

В еднонишковите програми можем да вземем StringBuilder . И все пак, печалбата от производителността на StringBuilder над StringBuffer може да е твърде малка, за да оправдае замяната му навсякъде. Винаги е добра идея да профилирате приложението и да разберете характеристиките му за изпълнение по време на изпълнение, преди да извършите каквато и да е работа, за да замените едно изпълнение с друго.

И накрая, както винаги, кодът, използван по време на дискусията, може да бъде намерен в GitHub.