Stage 1: Java fundamentals, lesson 7 of 10

Strings, StringBuilder and text blocks

Beginner4 min read@since 15Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

String is immutable. Methods like toUpperCase() return a new string and leave the original alone. String literals are kept in the string pool, so identical literals share one object.

Always compare text with equals(), never with ==.

To build text in a loop, use StringBuilder (Java 5). It avoids creating a new String on every +.

Handy modern methods: isBlank(), strip(), repeat() and lines() (Java 11), formatted() (Java 15). Text blocks (""", final in Java 15) make multi-line JSON, SQL and HTML readable.

Creating strings and the string pool

String literals are stored once in the string pool and shared. new String("x") always creates a new object, which you almost never need. intern() returns the pooled copy.

Java
String a = "java";
String b = "java";               // same pooled object as a
String c = new String("java");   // a new object on the heap

System.out.println(a == b);           // true  (same object)
System.out.println(a == c);           // false (different objects)
System.out.println(a == c.intern());  // true

Why strings are immutable

A String never changes after it's created; methods such as toUpperCase return a new string. That makes strings safe to share between threads, safe as HashMap keys (the hash is cached), and safe to use for things like file paths and class names.

Java
String s = "hello";
s.toUpperCase();         // result thrown away: s is still "hello"
s = s.toUpperCase();     // "HELLO": keep the new string

Comparing strings

  • equals compares content; == compares references (a classic bug).
  • equalsIgnoreCase ignores case.
  • compareTo orders strings alphabetically (negative, zero or positive).
  • Objects.equals(a, b) is null-safe. So is "literal".equals(input).
Java
String input = readName();
if ("admin".equals(input)) { }          // no NPE if input is null
"apple".compareTo("banana");            // negative: apple comes first
"Java".equalsIgnoreCase("JAVA");        // true

Everyday String methods

The methods you'll use constantly. substring(begin, end) excludes end. strip (Java 11) understands Unicode spaces; trim only removes ASCII ones.

Java
String s = "  Hello, Java World  ";
s.length();                    // 20
s.strip();                     // "Hello, Java World"
s.strip().charAt(0);           // 'H'
s.strip().substring(7, 11);    // "Java"
s.indexOf("Java");             // 9
s.contains("World");           // true
s.strip().startsWith("Hello"); // true
s.replace("Java", "Spring");   // "  Hello, Spring World  "
s.isBlank();                   // false  (Java 11)
"ab".repeat(3);                // "ababab" (Java 11)
"a\nb\nc".lines().count();     // 3 (Java 11)

Splitting and joining

split takes a regular expression, so special characters such as . and | must be escaped. String.join and Collectors.joining do the reverse.

Java
"a,b,,c".split(",");            // [a, b, , c]
"1.2.3".split("\\.");           // [1, 2, 3] (escape the dot)
"k=v=w".split("=", 2);          // [k, v=w] (limit)

String csv = String.join(", ", List.of("Pune", "Delhi", "Goa"));
String ids = orders.stream().map(Order::id).collect(Collectors.joining("|"));

StringBuilder and StringBuffer

Building a string piece by piece? Use StringBuilder: it's mutable, so it doesn't create a new object each time. StringBuffer is the older, synchronized version; you rarely need it.

Java
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
    sb.append(i).append(i < 5 ? "," : "");
}
sb.insert(0, "[").append("]");        // "[1,2,3,4,5]"
sb.reverse();                          // "]5,4,3,2,1["
String result = sb.toString();

Concatenation and performance

Joining with + in one expression is fine: since Java 9 the compiler uses an optimised strategy. Inside a loop, though, each += creates a new string, so building a large string that way is slow (O(n²)). Use StringBuilder or Collectors.joining in loops.

Formatting and text blocks

String.format and formatted (Java 15) build text from a pattern. Text blocks (Java 15) hold multi-line text such as JSON, SQL or HTML without escaping quotes; a trailing \ joins lines.

Java
String line = "%-10s %8.2f".formatted("Total", 1499.5);   // "Total       1499.50"

String json = """
    {
      "name": "Asha",
      "city": "Pune"
    }
    """;

String sql = """
    SELECT id, name FROM course \
    WHERE published = true""";

char, Unicode and emoji

A char is one UTF-16 unit, so characters outside the basic range (many emoji, some scripts) take two chars. Use codePoints() to count or iterate real characters, and the Character class to test them.

Java
String s = "Hi šŸ‘‹";
s.length();                       // 5 (the emoji is 2 chars)
s.codePointCount(0, s.length());  // 4 real characters
Character.isLetter('क');          // true
Character.isDigit('7');           // true
Character.toUpperCase('a');       // 'A'

Converting to and from strings

String.valueOf turns anything into a string. Integer.parseInt and friends go the other way and throw NumberFormatException on bad input, so validate or catch it.

Java
String s1 = String.valueOf(42);
String s2 = Integer.toString(255, 16);     // "ff"
int n = Integer.parseInt("123");
double d = Double.parseDouble("3.14");
char[] chars = "java".toCharArray();
String back = new String(chars);
byte[] utf8 = "₹100".getBytes(StandardCharsets.UTF_8);

try {
    Integer.parseInt("12a");
} catch (NumberFormatException e) {
    System.out.println("Not a number");
}

Example

Java
String a = "java";
String b = new String("java");
System.out.println(a == b);          // false: different objects
System.out.println(a.equals(b));     // true: same text

StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 3; i++) sb.append(i).append(',');
System.out.println(sb);              // 1,2,3,

String json = """
    {
      "course": "Spring Boot",
      "free": true
    }
    """;                             // Java 15+

System.out.println("  hi  ".strip().repeat(2));   // hihi (Java 11+)

Common mistake

Using == to compare user input with a literal. It may pass in tests (because literals are pooled) and then fail in production.

Under the hood

Since Java 9, compact strings store Latin-1 text in one byte per character, roughly halving memory for most strings. Simple concatenation like s1 + s2 compiles to an invokedynamic call to StringConcatFactory, so it's fast; only repeated concatenation inside loops is slow. intern() adds a string to the pool manually.

Check yourself

What does "hello".toUpperCase() do to the original string?

How this connects

Part of Java from zero, Crack the Java interview, Upgrade from Java 8 to Java 25.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.