Derek Peirce
11/19/2025, 6:13 AMfun foo(s: String): String {
return "bar" + s.substring(1, 7)
}
becomes in bytecode:
public static final String foo(@NotNull String s) {
Intrinsics.checkNotNullParameter(s, "s");
StringBuilder var10000 = (new StringBuilder()).append("bar");
String var10001 = s.substring(1, 7);
Intrinsics.checkNotNullExpressionValue(var10001, "substring(...)");
return var10000.append(var10001).toString();
}
Ideally, this would instead become:
public static final String foo(@NotNull String s) {
Intrinsics.checkNotNullParameter(s, "s");
StringBuilder var10000 = (new StringBuilder()).append("bar").append(s, 1, 7).toString();
}
to eliminate one string creation and a nullability check on a method that shouldn't need it.JP Sugarbroad
11/19/2025, 9:37 PMDerek Peirce
11/19/2025, 11:54 PM@Benchmark
public String buildStringDirect() {
StringBuilder builder = new StringBuilder();
Random random = new Random(153);
for (int k = 0; k < 500; k++) {
builder.append(string, random.nextInt(50), 50 + random.nextInt(100));
}
return builder.toString();
}
@Benchmark
public String buildStringWithSubstrings() {
StringBuilder builder = new StringBuilder();
Random random = new Random(153);
for (int k = 0; k < 500; k++) {
builder.append(string.substring(random.nextInt(50), 50 + random.nextInt(100)));
}
return builder.toString();
}
with string containing arbitrary lorem ipsum, and got these results:
Benchmark Mode Cnt Score Error Units
StringBenchmark.buildStringDirect avgt 10 24.915 ± 0.290 us/op
StringBenchmark.buildStringWithSubstrings avgt 10 28.771 ± 0.507 us/op
so the substring calls add roughly +15% overhead in this case.ephemient
11/20/2025, 4:19 AMephemient
11/20/2025, 4:25 AMString.subSequence() could return a CharSequence representing a similar non-copying slice (java.lang.String doesn't, but several projects have their own wrappers that do, such as https://github.com/JetBrains/intellij-community/blob/master/platform/util/base/multiplatform/src/com/intellij/util/text/CharSequenceSubSequence.kt)