Observation
The Java inspection 'StringBuilder' can be replaced with 'String' (ID StringBufferReplaceableByString) highlights code that uses a local StringBuilder, StringBuffer, or StringJoiner and suggests rewriting it as a single String concatenation. The suggestion is sometimes assumed to be wrong, with two common objections:
- The builder is needed for conditional concatenation.
-
StringBufferis thread-safe and cannot be replaced with simple concatenation.
Reasoning
The inspection reports correctly. It triggers only on a local builder that is created, filled with a straight-line chain of append calls, and immediately converted to a String within the same method — a builder that never leaves the method and has no control-flow logic between the appends.
The suggested replacement is safe for three reasons:
-
No performance loss. The Java compiler (
javac) already compiles plain+string concatenation to equivalentStringBuilderoperations — on JDK 9 and later, to aninvokedynamiccall tomakeConcatWithConstants. The bytecode of a hand-written straight-lineStringBuilderchain and the bytecode of the equivalent+concatenation are nearly identical, so theStringform is equally or more efficient. The inspection only reports when the replacement causes no significant performance drawback on modern JVMs. -
Conditional concatenation is not flagged. When
if,while, orforlogic sits between theappendcalls, or the builder's declaration and use are separated across statements, the inspection does not trigger. The "conditional concatenation" case is therefore not reported. -
Thread safety does not apply. The flagged builder is method-local and is never shared between threads, so the synchronization in
StringBufferhas no effect and can be removed without changing behavior.
This behavior is long-standing and has been confirmed as working-as-designed by the IntelliJ IDEA team (Code Analysis. Inspection subsystem); the corresponding reports were declined or answered with bytecode evidence.
Worked example showing the builder and the concatenation compile to the same code
To see why the replacement is safe, compile the class below and decompile the resulting .class file in IntelliJ IDEA (open the compiled class from the Project tool window; the bundled Fernflower decompiler displays the recreated source). toString1() uses an explicit StringBuilder chain, while toString2() uses plain + concatenation:
class ConcatenationTest {
private Object productKey = null;
private int features = 1;
public String toString1() {
return new StringBuilder().append('[').append(productKey == null ? "" : productKey)
.append("][").append(features).append(']').toString();
}
public String toString2() {
return String.valueOf('[') + (productKey == null ? "" : productKey) + "][" + features + ']';
}
}
After decompiling, the explicit StringBuilder chain in toString1() is reconstructed as the same kind of + concatenation the inspection recommends:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
class ConcatenationTest {
private Object productKey = null;
private int features = 1;
ConcatenationTest() {
}
public String toString1() {
return "" + '[' + (this.productKey == null ? "" : this.productKey) + "][" + this.features + ']';
}
public String toString2() {
String var10000 = String.valueOf('[');
return var10000 + String.valueOf(this.productKey == null ? "" : this.productKey) + "][" + this.features + "]";
}
}
Both methods compile to equivalent code, confirming that the hand-written builder offers no advantage over the concatenation the inspection suggests.
Workaround
No code change is required for correctness. The inspection result is accurate, and applying the suggested quick-fix produces equivalent but shorter and simpler code.
If the warning is unwanted, suppress or disable it:
- Suppress a single occurrence: place the caret on the highlighted code, press Alt+Enter, expand the inspection's submenu, and choose a suppression option (statement, method, or class).
- Disable the inspection globally: open Settings/Preferences | Editor | Inspections | Java | Verbose or redundant code constructs, select 'StringBuilder' can be replaced with 'String', and clear its checkbox. The same dialog can lower the severity or limit the scope instead of disabling the inspection entirely.
Reference: Inspectopedia: 'StringBuilder' can be replaced with 'String'.
Comments
0 comments
Please sign in to leave a comment.