W3docs

Java String Concatenation

Join strings in Java using the + operator, concat(), and StringBuilder, and compare their performance.

"Concatenation" just means joining strings end to end. Java gives you several ways to do it — +, concat, String.format, text blocks, StringBuilder, String.join. They differ in readability and, when looped, in performance.

The + operator

+ is the everyday way:

String first = "Ada";
String last = "Lovelace";
String full = first + " " + last;     // "Ada Lovelace"

It also converts non-strings to strings via their toString():

int age = 36;
String s = "Age: " + age;             // "Age: 36"

Behind the scenes the compiler turns a + b + c into a single StringBuilder.append(...).append(...).toString(). So one chained + expression is efficient.

concat

String.concat(other) returns this string followed by other:

"Hello, ".concat("World!");    // "Hello, World!"

It's effectively the same as +, but only accepts a String (no autoconversion). Most code just uses +.

String.format and formatted

For multi-piece concatenation with type-specific formatting, String.format is cleaner than long chains of +:

String name = "Ada";
int age = 36;
String s = String.format("%s is %d years old", name, age);

Since Java 15, the instance method formatted is equivalent and reads left-to-right:

"%s is %d years old".formatted(name, age);

Text blocks for multi-line

For multi-line strings, the text-block syntax (Java 15+) avoids long \n chains:

String json = """
        {
          "name": "%s",
          "age": %d
        }
        """.formatted(name, age);

StringBuilder — for loops

Each + on a String creates a new object. In a loop with thousands of iterations, that's a lot of garbage. Use StringBuilder instead — it has a mutable internal buffer:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("line ").append(i).append("\n");
}
String result = sb.toString();

The StringBuilder methods you'll use:

  • append(any) — add to the end (returns the builder so you can chain).
  • insert(index, any) — insert at a position.
  • delete(start, end) — remove a range.
  • reverse() — reverse the builder's contents.
  • length() and setLength(n) — read / truncate.
  • toString() — produce the final String.

There's also StringBuffer, which is identical but thread-safe (every method is synchronized). You almost never need it — use StringBuilder unless you genuinely share the builder between threads.

String.join — for collections

When you have a collection of strings and a separator, String.join is the cleanest:

String csv = String.join(",", "a", "b", "c");        // "a,b,c"
String csv2 = String.join(", ", List.of("a", "b", "c"));   // "a, b, c"

For more advanced joining (collectors, conditional inclusion), see streams' Collectors.joining later in the book.

When to use which

A rough decision tree:

  • One or two pieces, readable left-to-right+.
  • Several pieces with type formattingString.format or formatted.
  • Multi-line literal → text block, optionally with .formatted.
  • Building piece by piece in a loopStringBuilder.
  • Joining a collection with a separatorString.join.

For small concatenations, modern compilers and the JVM (with the invokedynamic-based string concat introduced in Java 9) make + very fast — performance is not a reason to avoid it for simple cases.

A demonstration of the loop case

java— editable, runs on the server

What's next

Java Special Characters and Escape Sequences — what \n, \t, \", and the Unicode escapes do.

Practice

Practice

Which approach is best for building a long string inside a 10,000-iteration loop?