I would use StringBuilder
, not StringBuffer
. StringBuffer
is for multithreaded situations, and is therefore slower than StringBuilder
, as it doesn't synchronize. I tested the four basic ways of doing this listed by various answers in this thread.
Notice, though, the certain things I always do here; these should be the things your interviewer is really looking for:
- I never use
String += nextCharacter;
as it is much, much slower than using a StringBuilder
.
- I set the
initialCapacity
because doing that is always faster. If you don't, if the StringBuilder
gets full, it has to reallocate a new array and copy over, which is slow.
And the code:
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Random;
public class EveryOtherTest {
public static class StringBenchmark extends SimpleBenchmark {
private String input;
protected void setUp() {
Random r = new Random();
int length = r.nextInt(1000) + 1000;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append((char) ('A' + r.nextInt(26)));
}
input = sb.toString();
}
public String timeCharArrayForeach(int reps) {
String output = "";
Random r = new Random();
for (int i = 0; i < reps; i++) {
StringBuilder sb = new StringBuilder(input.length() / 2 + 1);
boolean use = false;
for (char c : input.toCharArray()) {
if(use) sb.append(c);
use = !use;
}
String newOutput = sb.toString();
if (r.nextBoolean()) output = newOutput; // Trick the JIT
}
return output;
}
public String timeCharArrayPlusTwo(int reps) {
String output = "";
Random r = new Random();
for (int i = 0; i < reps; i++) {
StringBuilder sb = new StringBuilder(input.length() / 2 + 1);
char[] charArray = input.toCharArray();
for(int j = 0; j < input.length(); j += 2) {
sb.append(charArray[j]);
}
String newOutput = sb.toString();
if (r.nextBoolean()) output = newOutput; // Trick the JIT
}
return output;
}
public String timeCharAt(int reps) {
String output = "";
Random r = new Random();
for (int i = 0; i < reps; i++) {
StringBuilder tmp = new StringBuilder(input.length() / 2 + 1);
for (int j = 0; j < input.length(); j += 2) {
tmp.append(input.charAt(j));
}
String newOutput = tmp.toString();
if (r.nextBoolean()) output = newOutput; // Trick the JIT
}
return output;
}
public String timeIterator(int reps) {
String output = "";
Random r = new Random();
for(int i = 0; i < reps; i++) {
StringBuilder buf = new StringBuilder(input.length() / 2 + 1);
StringCharacterIterator iterator = new StringCharacterIterator(input);
for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
buf.append(c);
iterator.next();
}
String newOutput = buf.toString();
if (r.nextBoolean()) output = newOutput; // Trick the JIT
}
return output;
}
public String timeRegex(int reps) {
String output = "";
Random r = new Random();
for(int i = 0; i < reps; i++) {
String newOutput = input.replaceAll("(?<!^).(.)", "$1");
if (r.nextBoolean()) output = newOutput; // Trick the JIT
}
return output;
}
}
public static void main(String... args) {
Runner.main(StringBenchmark.class, args);
}
}
Results:
0% Scenario{vm=java, trial=0, benchmark=CharArrayForeach} 2805.55 ns; ?=688.96 ns @ 10 trials
20% Scenario{vm=java, trial=0, benchmark=CharArrayPlusTwo} 3428.48 ns; ?=475.32 ns @ 10 trials
40% Scenario{vm=java, trial=0, benchmark=CharAt} 2138.68 ns; ?=379.44 ns @ 10 trials
60% Scenario{vm=java, trial=0, benchmark=Iterator} 3963.94 ns; ?=389.53 ns @ 10 trials
80% Scenario{vm=java, trial=0, benchmark=Regex} 58743.66 ns; ?=10850.33 ns @ 10 trials
benchmark us linear runtime
CharArrayForeach 2.81 =
CharArrayPlusTwo 3.43 =
CharAt 2.14 =
Iterator 3.96 ==
Regex 58.74 ==============================
vm: java
trial: 0