String Concatenation

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 94 of 133

Concatenation means joining strings end to end. Java offers several ways to do it: the + operator, the concat method, String.join, StringJoiner, Collectors.joining, StringBuilder, and formatting methods. They produce the same kind of result but differ in readability, how they treat non-string values and null, and performance when text is built up repeatedly. Choosing the right one is a small decision that comes up constantly.

The + Operator

When at least one operand of + is a String, Java performs concatenation instead of addition:

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

int year = 1815;
String info = full + " was born in " + year;   // "Ada Lovelace was born in 1815"

The non-string operand is converted to text automatically: numbers become their decimal form, chars become one-character strings, booleans become "true"/"false", and objects are converted by calling their toString() method.

Evaluation order matters

+ is evaluated left to right. Once the running result is a String, every following + is concatenation:

System.out.println(1 + 2 + "3" + 4 + 5);    // 3345

Step by step: 1 + 2 is integer addition (3); 3 + "3" is concatenation ("33"); then "33" + 4 gives "334", and + 5 gives "3345". Use parentheses to force arithmetic:

System.out.println("Sum: " + 4 + 5);        // Sum: 45
System.out.println("Sum: " + (4 + 5));      // Sum: 9
System.out.println("Total: " + 2 * 3);      // Total: 6   (* binds tighter than +)

char is a number unless a String is involved

System.out.println("" + 'a' + 'b');         // ab
System.out.println('a' + 'b');              // 195: 97 + 98, integer addition

Two char values added together produce an int. Starting with a string, or using String.valueOf(c), forces concatenation.

null becomes "null"

String name = null;
System.out.println("Name: " + name);        // Name: null

Concatenation never throws for null; it inserts the four characters null. That is convenient for debug logging but almost never what a user should see, so check values or supply defaults (Objects.requireNonNullElse(name, "guest")) before building user-facing text.

Compound assignment

String path = "home";
path += "/docs";
path += "/java";                            // "home/docs/java"

a += b is shorthand for a = a + b. It creates a new string each time; the original string object is unchanged.

The concat Method

String s = "Java".concat(" ").concat("21");   // "Java 21"

concat accepts only a String argument (no automatic conversion of numbers) and throws NullPointerException if the argument is null. It is rarely preferred over +.

How + Is Compiled

For a single expression such as a + " " + b + "!", the compiler generates efficient code. Since Java 9, it uses an invokedynamic call to a JVM-provided concatenation strategy that sizes the result once and copies each part directly. A single concatenation expression is therefore fast and needs no manual optimization.

Concatenation in Loops: Use StringBuilder

The problem appears when a string is built up across loop iterations:

String result = "";
for (int i = 0; i < 10_000; i++) {
    result += i + ",";              // creates a new, longer string every time
}

Each += copies everything built so far into a brand-new string. The total work grows with the square of the output length: for 10,000 items, the program copies tens of millions of characters and creates 10,000 discarded strings.

StringBuilder keeps a single growable buffer and appends into it:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10_000; i++) {
    sb.append(i).append(',');
}
String result = sb.toString();

The work now grows linearly with the output size. append is overloaded for every primitive type and for objects, and returns the builder itself, so calls can be chained. StringBuilder has its own lesson.

SituationUse
One expression joining a few values+
Appending inside a loopStringBuilder
Joining items with a separatorString.join, StringJoiner, Collectors.joining
Mixing text with formatted numbersString.format / formatted

Joining with a Separator

Putting a separator between items (but not after the last one) is so common that Java has dedicated tools.

String.join

String csv = String.join(",", "red", "green", "blue");          // "red,green,blue"
String path = String.join("/", List.of("home", "ada", "docs")); // "home/ada/docs"

It accepts varargs or any Iterable of CharSequences.

StringJoiner

StringJoiner adds items one at a time, with an optional prefix and suffix:

StringJoiner sj = new StringJoiner(", ", "[", "]");
sj.add("Java").add("Bash").add("C");
System.out.println(sj);                     // [Java, Bash, C]

StringJoiner empty = new StringJoiner(", ", "[", "]");
empty.setEmptyValue("none");
System.out.println(empty);                  // none

It is useful when items are added conditionally inside a loop.

Collectors.joining

With streams, Collectors.joining does the same job:

String names = students.stream()
        .map(Student::name)
        .collect(Collectors.joining(", "));

String bracketed = Stream.of("a", "b").collect(Collectors.joining(" | ", "[", "]"));   // [a | b]

All three avoid the classic loop bug of a trailing separator ("a, b, c, ").

Formatting Instead of Concatenating

When text mixes several values with formatting needs, a format string is often clearer than a chain of +:

String msg1 = "Order " + id + " for " + name + ": " + qty + " x " + price;
String msg2 = String.format("Order %d for %s: %d x %.2f", id, name, qty, price);
String msg3 = "Order %d for %s: %d x %.2f".formatted(id, name, qty, price);

The format version shows the shape of the output at a glance and controls number formatting. The String Format lesson covers format specifiers.

Practical Example: Receipt and CSV Export

import java.util.*;
import java.util.stream.Collectors;

public class Concat {
    record Line(String item, int qty, double price) { }

    static String csvRow(List<String> fields) {
        StringJoiner row = new StringJoiner(",");
        for (String f : fields) {
            row.add(f.contains(",") || f.contains("\"")
                    ? "\"" + f.replace("\"", "\"\"") + "\""
                    : f);
        }
        return row.toString();
    }

    public static void main(String[] args) {
        List<Line> lines = List.of(
            new Line("Notebook", 3, 80), new Line("Pen, blue", 10, 12.5), new Line("Bag \"XL\"", 1, 1499));

        StringBuilder receipt = new StringBuilder();
        double total = 0;
        for (Line l : lines) {
            double amount = l.qty() * l.price();
            total += amount;
            receipt.append(String.format("%-12s %3d x %8.2f%n", l.item(), l.qty(), l.price()));
        }
        receipt.append("-".repeat(28)).append('\n')
               .append(String.format("%-12s %15.2f", "TOTAL", total));
        System.out.println(receipt);

        System.out.println(csvRow(List.of("item", "qty", "price")));
        for (Line l : lines) {
            System.out.println(csvRow(List.of(l.item(), String.valueOf(l.qty()), String.valueOf(l.price()))));
        }

        String tags = lines.stream().map(Line::item)
                .collect(Collectors.joining(" | ", "[", "]"));
        System.out.println(tags);
    }
}

Output:

Notebook       3 x    80.00
Pen, blue     10 x    12.50
Bag "XL"       1 x  1499.00
----------------------------
TOTAL                1864.00
item,qty,price
Notebook,3,80.0
"Pen, blue",10,12.5
"Bag ""XL""",1,1499.0
[Notebook | Pen, blue | Bag "XL"]

Each technique has a role:

  • StringBuilder for the receipt. Lines are appended inside a loop, and each line is produced by String.format so the columns align.
  • repeat(28) for the divider. It builds the rule of hyphens without a loop.
  • StringJoiner for CSV fields. It puts commas only between fields. Fields that contain a comma or a quote are wrapped in quotes, and embedded quotes are doubled, following the CSV convention, so that Pen, blue stays a single field when the file is opened in a spreadsheet.
  • Collectors.joining for the tag line. It joins the item names with a separator and wraps them in brackets.

None of the output was built with += in a loop.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about String Concatenation and get answers drawn from it.

Signed-in readers only.