V
Vel·ToolKit
Simple · Fast · Ready to use
EN
Chapter 16 of 20

Strings & Text Blocks

Immutable String, StringBuilder, Text Blocks, format, encoding

What's Special About Strings in Java

Use cases: log messages, HTTP request/response, SQL building, template rendering, CLI argument handling. Java's String is designed for "safe + fast" — it is immutable, cached in the literal pool, and stays valid as a Map key, so it flows through systems especially often.

String Is Immutable + the String Literal Pool

A String's content cannot change after creation: any "modifying" operation (replace, trim, toLowerCase…) returns a new object. Identical literals in source (like "hello") are pooled by the JVM into one object, saving memory. new String("hello") forces a new object, bypassing the pool — **don't use new String** unless you have a specific reason.

// StringIdentity.java
public class StringIdentity {
    public static void main(String[] args) {
        String a = "hello";
        String b = "hello";              // same pooled object
        String c = new String("hello");  // new object, bypasses the pool
        String d = c.intern();             // explicitly interned, gets the pooled object again

        System.out.println(a == b);   // true (same object)
        System.out.println(a == c);   // false (c was new'd)
        System.out.println(a == d);   // true (interned into the pool)

        // always compare content with equals
        System.out.println(a.equals(c)); // true
    }
}

StringBuilder: Essential for Heavy Concatenation

Use cases: concatenating strings in a loop, building CSV / SQL / log lines. String's + creates a new object every time; using + in a loop is an O(n²) performance disaster. StringBuilder is a mutable internal buffer with a single final toString() — the gap can reach hundreds of times. StringBuffer is the thread-safe version of StringBuilder (with synchronized), rarely used day to day.

// Builder.java
public class Builder {
    public static void main(String[] args) {
        // ❌ bad example: + in a loop
        // String s = "";
        // for (int i = 0; i < 100_000; i++) s += i;     // extremely slow

        // ✅ StringBuilder
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 5; i++) {
            sb.append(i).append(",");
        }
        if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1);
        System.out.println(sb);          // 0,1,2,3,4

        // fluent API
        String json = new StringBuilder()
            .append("{\"name\":\"").append("Alice").append("\",")
            .append("\"age\":").append(30).append("}")
            .toString();
        System.out.println(json);
    }
}

Text Blocks: Multi-line Strings (Java 15+)

Use cases: embedded SQL, JSON, HTML, SQL templates, error messages — previously you wrote a pile of \n and escaped quotes; now use a triple-quoted block. The compiler auto-strips indentation to the leftmost-aligned position.

// TextBlock.java
public class TextBlock {
    public static void main(String[] args) {
        String sql = """
                SELECT id, name, email
                FROM users
                WHERE status = 'active'
                  AND created_at > ?
                ORDER BY id
                """;
        System.out.println(sql);

        String json = """
                {
                    "name": "Alice",
                    "age": 30,
                    "tags": ["java", "go"]
                }
                """;
        System.out.println(json);

        // \<newline> line continuation: joins into a single line
        String long1 = """
                this is a very \
                long single line
                """;
        System.out.println(long1);
    }
}

String.format / formatted

Use cases: building strings with placeholders — logs, error messages, user panels. printf-style %s %d %.2f, etc. Java 15+ added the instance method "...".formatted(args) for better readability.

// FormatDemo.java
public class FormatDemo {
    public static void main(String[] args) {
        String name = "Alice";
        int age = 30;
        double score = 87.5;

        // classic: String.format
        String s1 = String.format("%s is %d (score=%.2f)", name, age, score);
        System.out.println(s1);

        // Java 15+: instance method
        String s2 = "%s is %d (score=%.2f)".formatted(name, age, score);
        System.out.println(s2);

        // width alignment, zero-padding
        System.out.println(String.format("%-10s|%5d|%08d", "id", 42, 7));
        // id        |   42|00000007
    }
}

String.join and split

join glues collection elements with a separator, common for CSV, SQL IN lists, log formatting. split divides by a regex. Note: split's argument is a regex — to split on . write "\\.".

// JoinSplit.java
import java.util.List;

public class JoinSplit {
    public static void main(String[] args) {
        List<String> tags = List.of("java", "go", "rust");
        String csv = String.join(", ", tags);
        System.out.println(csv);              // java, go, rust

        // build a SQL IN list (PreparedStatement placeholders are actually safer)
        String inList = String.join(",", tags);
        String sql = "SELECT * FROM lang WHERE name IN (" + inList + ")";
        System.out.println(sql);

        // split: by regex
        String line = "a, b,  c , d";
        String[] parts = line.split("\\s*,\\s*");  // any whitespace + comma + any whitespace
        for (String p : parts) System.out.println("[" + p + "]");

        // split on a period: needs escaping
        String[] segs = "www.example.com".split("\\.");
        for (String s : segs) System.out.println(s);
    }
}

Common Methods Cheat Sheet

// StringApi.java
public class StringApi {
    public static void main(String[] args) {
        String s = "  Hello, Java World!  ";

        // length / index access
        System.out.println(s.length());
        System.out.println(s.charAt(2));

        // case, whitespace
        System.out.println(s.trim());                 // trim leading/trailing ASCII whitespace
        System.out.println(s.strip());                // trim leading/trailing Unicode whitespace (Java 11+, recommended)
        System.out.println(s.toLowerCase());
        System.out.println(s.toUpperCase());

        // substring and search
        System.out.println(s.substring(2, 7));        // Hello
        System.out.println(s.indexOf("Java"));
        System.out.println(s.contains("World"));
        System.out.println(s.startsWith("  Hello"));
        System.out.println(s.endsWith("!  "));

        // replace
        System.out.println(s.replace("World", "Universe"));
        System.out.println(s.replaceAll("\\s+", "_")); // regex replace

        // emptiness check
        System.out.println("".isEmpty());             // true
        System.out.println("   ".isBlank());          // true (Java 11+)

        // repeat (Java 11+)
        System.out.println("=".repeat(10));
    }
}

Strings and Bytes (Encoding)

Use cases: network send/receive, writing files, Base64 encoding, crypto hashing. String <-> byte[] conversion **must** explicitly specify a charset (prefer UTF-8); otherwise it uses the platform default — which behaves differently across OSes and is a classic source of garbled text.

// Bytes.java
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class Bytes {
    public static void main(String[] args) {
        String s = "你好 Java";

        // String -> byte[]
        byte[] utf8 = s.getBytes(StandardCharsets.UTF_8);
        byte[] gbk  = s.getBytes(java.nio.charset.Charset.forName("GBK"));
        System.out.println("utf8 bytes = " + utf8.length); // 11
        System.out.println("gbk  bytes = " + gbk.length);  // 9

        // byte[] -> String
        String back = new String(utf8, StandardCharsets.UTF_8);
        System.out.println(back);

        // view as hex
        StringBuilder hex = new StringBuilder();
        for (byte b : utf8) hex.append(String.format("%02x ", b));
        System.out.println(hex);
    }
}