liveBook · Manning

StringBuilder

As explained in 100 Java Mistakes and How to Avoid Them

StringBuilder is a mutable Java character sequence class that supports efficient string construction and modification.

StringBuilder is mutable, but several familiar object conventions do not apply. Its equals() method uses identity: two distinct builders with identical characters are not equal. Since Java 11, compareTo() compares builder contents, creating an important mismatch between equality and ordering. section 7.2 section 8.6

Compare builder contents deliberately

For content equality, use builder1.compareTo(builder2) == 0. Alternatively, builder1.toString().contentEquals(builder2) works but creates a String; character-by-character comparison is another option. Do not assume equals() tests the characters. section 7.2

Using a mutable builder as a HashMap key or HashSet element is risky. The identity-based equals() and hashCode() normally differ from content-based compareTo(); under particular hash-collision conditions, HashMap or HashSet may rely on compareTo(), and appending can make contains() fail. section 8.6

public static void main(String[] args) {
  Set<StringBuilder> set = new HashSet<>();

  for (int count = 0; count < 40; count++) {     #1
    set.add(firstBucketStringBuilder());       
  }    
  int[] hashCodes = set.stream()     #2
        .mapToInt(Object::hashCode)    
        .sorted().toArray();   
  StringBuilder sb =    
    Stream.generate(StringBuilder::new)   
        .filter(b -> Arrays.binarySearch(  
              hashCodes, b.hashCode()) >= 0)    
        .findFirst().get();   
  set.add(sb);     #3
  System.out.println(set.contains(sb));     #4
  sb.append("b");     #5
  System.out.println(set.contains(sb));     #6
}

static StringBuilder firstBucketStringBuilder() {
  while (true) {
    StringBuilder sb = new StringBuilder("a");
    int hc = sb.hashCode();     #7
    if (((hc ^ (hc >>> 16)) & 0x3F) == 0) {   
      return sb;    
    }   
  }
}

This collision-focused demonstration adds a StringBuilder to a HashSet, mutates it with append(), then shows that a later contains() lookup can fail. section 8.6

A char passed to the one-argument constructor is not initial content. new StringBuilder('[') selects StringBuilder(int capacity): '[' widens to 91, so the opening bracket is absent. Use a string literal for initial text, or create an empty builder and append the character. section 9.1

StringBuilder sb = new StringBuilder('[');    #1
sb.append(value);
sb.append(']');

The snippet isolates the overload mistake: the intended opening bracket becomes buffer capacity rather than builder content. section 9.1

Prevent common StringBuilder mistakes:

  • Use "[" rather than '[' when supplying initial content to the constructor. section 9.1
  • Cover UI messages with unit tests to catch missing characters. section 9.1
  • Enable relevant inspections: IntelliJ IDEA, SonarLint S1317, or Error Prone StringBuilderInitWithChar detect char-constructor calls. section 9.1

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains equality and overload behavior with focused snippets, then qualifies HashSet failures by implementation-dependent collision conditions.
Examples
Uses equal-looking builders, a collision-driven HashSet mutation demonstration, and new StringBuilder('[') missing its bracket.
What it assumes
Assumes familiarity with Java object equality, constructors, collections, and method calls; it does not teach them from zero.
What you can do after
Diagnose/debug identity-versus-content comparisons and char-constructor overload errors; avoid mutable builders as collection keys.
How it connects
Connects StringBuilder to equals(), compareTo(), hashCode(), HashMap, HashSet, static analysis, and unit tests.

Also explained in

Compare how 2 books explain StringBuilder →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.