Strings in Java

String is an immutable object with a shared literal pool, and both facts explain how comparison, concatenation and performance behave.

Definition

A String is an object representing a sequence of characters. It is a reference type, not a primitive, and it is immutable: once created, the characters it holds can never change.

Creating strings

String a = "Java";                  // literal, uses the string pool
String b = new String("Java");       // explicitly a new object, avoid this
String c = String.valueOf(2026);     // "2026"
String d = "Ja" + "va";              // folded to a literal at compile time

Immutability

String name = "chennai";
name.toUpperCase();               // result discarded, name unchanged
System.out.println(name);         // chennai

name = name.toUpperCase();        // rebinding the variable is what works
System.out.println(name);         // CHENNAI

Every method that appears to modify a string in fact returns a new one. Ignoring the return value is one of the most common early mistakes in Java.

Why immutability was chosen

  • Safe sharing. Many references can point at one string with no risk, including across threads.
  • Reliable hash codes. The hash cannot drift, which makes strings dependable map keys.
  • Pooling becomes possible. Identical literals can be shared only because nobody can change them.
  • Security. A file path or connection string cannot be altered after it has been validated.

The string pool

String a = "Java";
String b = "Java";
String c = new String("Java");

System.out.println(a == b);           // true  - the same pooled object
System.out.println(a == c);           // false - c is a distinct object
System.out.println(a.equals(c));      // true  - same characters
System.out.println(a == c.intern());  // true  - intern returns the pooled instance

String literals are stored in a shared area called the string pool, which lives in the heap. Two identical literals therefore refer to one object. new String("Java") deliberately bypasses the pool and creates a second object, which is why it is almost never useful.

Compare strings with equals, never with ==. Code that seems to work with == is relying on pooling, and it will fail the moment the string arrives from input, a file or a database.

Common operations

String text = "  Java Programming  ";

System.out.println(text.length());              // 21
System.out.println(text.trim());                // removes ASCII whitespace
System.out.println(text.strip());               // Unicode aware, preferred
System.out.println(text.isBlank());             // false
System.out.println(text.strip().charAt(0));     // J
System.out.println(text.indexOf("Program"));    // 7
System.out.println(text.contains("Java"));      // true
System.out.println(text.strip().substring(5));  // Programming
System.out.println(text.replace("Java", "Core"));
System.out.println("a,b,,c".split(",").length); // 4
System.out.println(String.join("-", "x", "y")); // x-y
System.out.println("ab".repeat(3));             // ababab
System.out.println(" Hi ".strip().toLowerCase());

Comparison methods

MethodUse for
equalsExact content equality
equalsIgnoreCaseCase insensitive equality
compareToOrdering, returns negative, zero or positive
isEmptyLength is zero
isBlankEmpty or whitespace only, since Java 11

Concatenation and performance

// Poor inside a loop: each pass builds a new String and copies everything
String report = "";
for (String line : lines) {
    report += line;          // quadratic work
}

// Correct
StringBuilder builder = new StringBuilder();
for (String line : lines) {
    builder.append(line);
}
String report = builder.toString();

A single expression such as "a" + b + "c" is fine; the compiler builds it efficiently. The problem is repeated concatenation across loop iterations, where a new object is created every time.

Text blocks

String query = """
        SELECT id, title
        FROM notes
        WHERE status = 'published'
        """;

Since Java 15 a text block preserves line breaks and strips the common leading indentation, which keeps embedded text readable.

Formatting

String line = String.format("%-10s %5.2f", "Total", 249.5);
String same = "%-10s %5.2f".formatted("Total", 249.5);   // Java 15 and later

Common mistakes

  • Comparing with == and being misled by pooling during testing.
  • Calling a method such as replace and discarding the result.
  • Building strings by concatenation inside a loop.
  • Using new String("..."), which allocates without benefit.
  • Assuming length() counts visible characters. It counts UTF-16 code units, so characters outside the basic plane count as two.
  • Calling a method on a string that may be null. Writing "active".equals(status) instead of status.equals("active") avoids it.

Best practices

  • Use equals for comparison and compareTo for ordering.
  • Prefer strip over trim, and isBlank over a length check.
  • Use StringBuilder for repeated appends and text blocks for multi line content.
  • Keep the constant on the left when comparing against a literal.
  • Do not put passwords in a String if they must be cleared from memory; a char[] can be overwritten.

Practice

  1. Predict each line of output in the pool example, then change c to a literal and predict again.
  2. Write a method that reports whether a string is a palindrome, ignoring case and spaces.
  3. Why does "a,b,,c".split(",") give four elements while "a,b,c,,".split(",") gives three?
  4. Count the occurrences of a word in a sentence without using a regular expression.
  5. Explain why building a 10000 line report with += is slow, in terms of objects created.

Conclusion

Strings are immutable objects with a shared pool of literals. Compare with equals, remember that every method returns a new string, and switch to StringBuilder the moment you are appending in a loop.

Written by Lorens Mishra

Software Engineer Notes Management System Administrator

Continue reading

All Java notes →
Java

Arrays in Java

An array is a fixed size object holding elements of one type, indexed from zero, with the length fixed at creation.

Read more
Java

Reflection in Java

Reflection inspects and manipulates classes at runtime. It powers most frameworks and should be rare in application code.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.