Strings

Reviewed & published by Brayan K

Strings are the most commonly used type in real-world Java. Every user input, every file name, every database query, every error message — they're all strings. In this lesson, you'll learn to search, compare, split, format, and efficiently build strings. You'll also learn the #1 Java gotcha: why == doesn't work for comparing strings.

Part of the free Java course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

💡 Real-World Analogy

A String is like a necklace of letter beads. Each bead is a character, and you can examine them, count them, or create a new necklace — but you can never change the beads on an existing necklace. Every "change" actually creates a brand new necklace. This is called immutability.

1️⃣ Creating Strings & Concatenation

You create strings by wrapping text in double quotes. You can combine strings using the + operator (concatenation):

// Creating strings
String name = "Alice";
String greeting = "Hello, World!";

// Concatenation — joining strings together
String message = "Hello, " + name + "!";
// → "Hello, Alice!"

// Concatenating different types (auto-converted to String)
int age = 25;
String info = name + " is " + age + " years old";
// → "Alice is 25 years old"

// ⚠️ Watch out for order of operations!
System.out.println("Score: " + 5 + 3);   // "Score: 53" (strings!)
System.out.println("Score: " + (5 + 3));  // "Score: 8"  (math first)

2️⃣ Immutability & The String Pool

Immutability means once a String is created, it can never be changed. Every method that seems to "modify" a string actually creates a brand new string and returns it. The original is untouched.

String name = "Alice";
name.toUpperCase();         // Creates "ALICE" but we don't store it!
System.out.println(name);   // Still "Alice" — original unchanged!

name = name.toUpperCase();  // ✅ Now name points to "ALICE"
System.out.println(name);   // "ALICE"

Java also maintains a String Pool — a special memory area that reuses identical string literals:

String a = "Hello";              // Goes to String Pool
String b = "Hello";              // Reuses same object!
String c = new String("Hello");  // Forces NEW object (bypasses pool)

a == b     // true  (same pool object)
a == c     // false (different objects!)
a.equals(c) // true  (same content ✓)

🔑 This is why == is unreliable for strings! It compares memory addresses, not content. Two strings can have identical text but be different objects in memory. Always use .equals().

3️⃣ Essential String Methods

These are the methods you'll use every day. Memorize these and you'll handle 90% of string tasks:

String text = "Hello, World!";

// === INSPECTING ===
text.length()              // 13 (number of characters)
text.charAt(0)             // 'H' (first character)
text.charAt(6)             // 'W' 
text.isEmpty()             // false
text.isBlank()             // false (Java 11+, checks whitespace too)

// === SEARCHING ===
text.contains("World")     // true
text.indexOf("World")      // 7 (position where "World" starts)
text.indexOf("xyz")        // -1 (not found)
text.lastIndexOf("l")      // 10 (last occurrence)
text.startsWith("Hello")   // true
text.endsWith("!")          // true

// === TRANSFORMING (returns NEW string!) ===
text.toUpperCase()         // "HELLO, WORLD!"
text.toLowerCase()         // "hello, world!"
text.substring(0, 5)       // "Hello" (from index 0 to 4)
text.substring(7)          // "World!" (from index 7 to end)
text.replace("World", "Java") // "Hello, Java!"
"  spaces  ".trim()        // "spaces"

// === SPLITTING & JOINING ===
"a,b,c".split(",")        // String[] {"a", "b", "c"}
String.join(" - ", "a", "b", "c")  // "a - b - c"
public class Main {
    public static void main(String[] args) {
        String text = "Hello, World!";
        System.out.println("Text: '" + text + "'");

        // 1. Inspecting
        System.out.println("\n1. INSPECTING:");
        System.out.println("   length: " + text.length());
        System.out.println("   charAt(0): '" + text.charAt(0) + "'");
        System.out.println("   charAt(7): '" + text.charAt(7) + "'");

        // 2. Searching
        System.out.println("\n2. SEARCHING:");
        System.out.println("   contains 'World': " + text.contains("World"));
        System.out.println("   indexOf 'World': " + text.indexOf("World"));
        System.out.println("   indexOf 'xyz': " + text.indexOf("xyz") + " (-1 = not found)");
        System.out.println("   startsWith 'Hello': " + text.startsWith("Hello"));
        System.out.println("   endsWith '!': " + text.endsWith("!"));

        // 3. Transforming (returns a NEW string)
        System.out.println("\n3. TRANSFORMING:");
        System.out.println("   toUpperCase: " + text.toUpperCase());
        System.out.println("   toLowerCase: " + text.toLowerCase());
        System.out.println("   substring(0,5): " + text.substring(0, 5));
        System.out.println("   substring(7): " + text.substring(7));
        System.out.println("   replace: " + text.replace("World", "Java"));

        // 4. Trim
        System.out.println("\n4. TRIM:");
        String padded = "   Hello   ";
        System.out.println("   Before: '" + padded + "'");
        System.out.println("   After:  '" + padded.trim() + "'");

        // 5. Split and Join
        System.out.println("\n5. SPLIT & JOIN:");
        String csv = "Java,Python,JavaScript,C++";
        String[] langs = csv.split(",");
        System.out.println("   Split length: " + langs.length);
        System.out.println("   Join: " + String.join(" | ", langs));

        // 6. Comparison (.equals vs ==)
        System.out.println("\n6. COMPARISON (equals vs ==):");
        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = "hello";
        System.out.println("   s1.equals(s2): " + s1.equals(s2) + " (same content)");
        System.out.println("   s1.equals(s3): " + s1.equals(s3) + " (case differs!)");
        System.out.println("   equalsIgnoreCase: " + s1.equalsIgnoreCase(s3));

        System.out.println("\nAlways use .equals() in Java, never == for strings!");
    }
}

4️⃣ String Comparison — The #1 Java Gotcha

This is the single most common bug Java beginners make. Let's be absolutely clear about it:

// ❌ WRONG — compares memory addresses, not content!
String input = scanner.nextLine();  // user types "yes"
if (input == "yes") { ... }  // MIGHT work, might not! Unreliable!

// ✅ CORRECT — compares actual text content
if (input.equals("yes")) { ... }

// ✅ Case-insensitive comparison
if (input.equalsIgnoreCase("YES")) { ... }

// ✅ Null-safe trick — put the constant first
if ("yes".equals(input)) { ... }  // Won't crash even if input is null!

// ❌ CRASH if input is null
if (input.equals("yes")) { ... }  // NullPointerException!

🔑 The rule: == checks "are these the exact same object in memory?" .equals() checks "do these contain the same text?" You almost always want .equals().

5️⃣ StringBuilder — Efficient String Building

Because strings are immutable, concatenation in a loop creates a new string object every iteration. For large loops, this wastes massive amounts of memory. Use StringBuilder instead:

// ❌ SLOW — creates 1000 temporary String objects!
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i + ", ";  // New String EVERY time
}

// ✅ FAST — uses one mutable buffer
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i).append(", ");
}
String result = sb.toString();

// StringBuilder methods:
sb.append("text");      // Add to end
sb.insert(0, "start");  // Insert at position
sb.delete(0, 5);        // Remove characters
sb.reverse();            // Reverse the content
sb.length();             // Current length
sb.toString();           // Convert to String

💡 Rule of thumb: If you're concatenating in a loop, use StringBuilder. For a few simple concatenations outside loops, regular + is fine.

6️⃣ String.format() — Clean Formatted Output

Instead of ugly concatenation with lots of + signs, use String.format() for readable, clean string construction:

String name = "Alice";
int age = 30;
double gpa = 3.857;

// ❌ Hard to read with concatenation
String msg1 = "Name: " + name + ", Age: " + age + ", GPA: " + gpa;

// ✅ Clean with String.format()
String msg2 = String.format("Name: %s, Age: %d, GPA: %.1f", name, age, gpa);
// → "Name: Alice, Age: 30, GPA: 3.9"

// Format specifiers:
// %s  = String
// %d  = integer
// %f  = floating-point
// %.2f = 2 decimal places
// %n  = newline
// %10s = right-padded to 10 chars
// %-10s = left-padded to 10 chars
public class Main {
    public static void main(String[] args) {
        // 1. StringBuilder in a loop
        System.out.println("1. STRING BUILDING IN A LOOP:");
        StringBuilder sb = new StringBuilder();
        for (int i = 1; i <= 10; i++) {
            sb.append("Item").append(i);
            if (i < 10) sb.append(", ");
        }
        System.out.println("   " + sb);

        // 2. Formatted output with String.format / printf
        System.out.println("\n2. FORMATTED OUTPUT:");
        String[] names = {"Alice", "Bob", "Charlie"};
        int[] ages = {20, 22, 19};
        double[] gpas = {3.85, 3.42, 3.91};
        System.out.printf("   %-10s%-5s%s%n", "Name", "Age", "GPA");
        System.out.println("   --------------------");
        for (int i = 0; i < names.length; i++) {
            System.out.printf("   %-10s%-5d%.2f%n", names[i], ages[i], gpas[i]);
        }

        // 3. Null-safe comparison (constant first)
        System.out.println("\n3. NULL-SAFE COMPARISON:");
        String input = null;
        // input.equals("yes") would throw NullPointerException!
        // "yes".equals(input) returns false safely.
        System.out.println("   \"yes\".equals(input): " + "yes".equals(input) + " (safe, no crash)");

        // 4. Building a report
        System.out.println("\n4. BUILDING A REPORT:");
        int[] scores = {85, 92, 78, 95, 88};
        int total = 0, max = scores[0], min = scores[0];
        for (int s : scores) {
            total += s;
            if (s > max) max = s;
            if (s < min) min = s;
        }
        double avg = total / (double) scores.length;
        StringBuilder report = new StringBuilder();
        report.append("=== Score Report ===\n");
        report.append("Students: ").append(scores.length).append("\n");
        report.append("Total:    ").append(total).append("\n");
        report.append(String.format("Average:  %.1f%n", avg));
        report.append("Highest:  ").append(max).append("\n");
        report.append("Lowest:   ").append(min).append("\n");
        report.append("Range:    ").append(max - min);
        System.out.println(report);

        System.out.println("\nStringBuilder for loops, String.format() for clean output!");
    }
}

7️⃣ Real-World String Patterns

Here are patterns you'll use constantly in real Java applications:

// Email validation (basic)
boolean validEmail = email.contains("@") && email.contains(".");

// File extension check
if (filename.endsWith(".java")) { ... }
if (filename.endsWith(".pdf") || filename.endsWith(".doc")) { ... }

// Parsing CSV data
String line = "Alice,25,3.85";
String[] parts = line.split(",");
String name = parts[0];        // "Alice"
int age = Integer.parseInt(parts[1]);  // 25
double gpa = Double.parseDouble(parts[2]); // 3.85

// Creating URL slugs
String slug = title.toLowerCase()
    .replaceAll("[^a-z0-9]+", "-")  // Replace non-alphanumeric
    .replaceAll("^-|-$", "");        // Remove leading/trailing dashes

// Sanitizing user input
String clean = input.trim()             // Remove leading/trailing spaces
    .replaceAll("\\s+", " ");        // Collapse multiple spaces
public class Main {
    static boolean isPalindrome(String str) {
        String clean = str.toLowerCase().replaceAll("[^a-z0-9]", "");
        return clean.equals(new StringBuilder(clean).reverse().toString());
    }

    static boolean isValidEmail(String email) {
        int at = email.indexOf("@");
        return email.contains("@") && email.contains(".")
                && at > 0 && email.lastIndexOf(".") > at;
    }

    public static void main(String[] args) {
        // 1. Palindrome checker
        System.out.println("1. PALINDROME CHECKER:");
        String[] words = {"racecar", "hello", "A man a plan a canal Panama", "level", "world"};
        for (String w : words) {
            System.out.println("   '" + w + "' -> " + (isPalindrome(w) ? "Palindrome!" : "Not a palindrome"));
        }

        // 2. Email validator
        System.out.println("\n2. EMAIL VALIDATOR:");
        String[] emails = {"[email protected]", "bob@", "@invalid", "[email protected]", "noatsign"};
        for (String e : emails) {
            System.out.printf("   %-20s%s%n", e, isValidEmail(e) ? "Valid" : "Invalid");
        }

        // 3. CSV parser
        System.out.println("\n3. CSV PARSER:");
        String csvData = "Alice,25,3.85\nBob,22,3.42\nCharlie,19,3.91";
        String[] rows = csvData.split("\n");
        System.out.printf("   %-10s%-5s%s%n", "Name", "Age", "GPA");
        System.out.println("   --------------------");
        for (String row : rows) {
            String[] cols = row.split(",");
            System.out.printf("   %-10s%-5s%.2f%n", cols[0], cols[1], Double.parseDouble(cols[2]));
        }

        // 4. URL slug generator
        System.out.println("\n4. URL SLUG GENERATOR:");
        String[] titles = {"Hello World!", "Java Programming 101", "How to Learn Fast & Easy"};
        for (String t : titles) {
            String slug = t.toLowerCase().replaceAll("[^a-z0-9]+", "-").replaceAll("^-|-$", "");
            System.out.println("   '" + t + "' -> /" + slug);
        }

        // 5. Character counter
        System.out.println("\n5. CHARACTER COUNTER:");
        String text = "Hello World";
        int vowels = 0, consonants = 0, spaces = 0;
        for (char ch : text.toLowerCase().toCharArray()) {
            if ("aeiou".indexOf(ch) >= 0) vowels++;
            else if (ch == ' ') spaces++;
            else if (ch >= 'a' && ch <= 'z') consonants++;
        }
        System.out.println("   Text: '" + text + "'");
        System.out.println("   Vowels: " + vowels + ", Consonants: " + consonants + ", Spaces: " + spaces);

        System.out.println("\nStrings are IMMUTABLE - every operation creates a new one!");
    }
}
public class Main {
    public static void main(String[] args) {
        // 🎯 YOUR TURN — replace each ___ using the hint beside it.

        String raw = "  Ada Lovelace,  London  ";

        // 1) Drop the spaces at both ends (the ones in the middle stay).
        String tidy = raw.___();                    // 👉 replace ___ with trim
        System.out.println("[" + tidy + "]");
        System.out.println("Length: " + tidy.___());  // 👉 replace ___ with length

        // 2) Where is the comma? -1 would mean "not found".
        int comma = tidy.___(",");                  // 👉 replace ___ with indexOf

        // 3) Cut from one index up to (but not including) another.
        String name = tidy.___(0, comma);           // 👉 replace ___ with substring
        String city = tidy.substring(comma + 1).trim();
        System.out.println("Name: " + name);
        System.out.println("City: " + city);

        System.out.println("Shouted: " + name.___());  // 👉 replace ___ with toUpperCase
        System.out.println("Starts with Ada? " + name.startsWith("Ada"));

        String other = "ada lovelace";
        // 4) == compares identity, so it is false even when the text matches.
        System.out.println("== says:       " + (name == other));
        System.out.println("equals says:   " + name.___(other));          // 👉 replace ___ with equals

        // 5) The one that ignores capitals — and the one you usually want.
        System.out.println("ignoring case: " + name.___(other));          // 👉 replace ___ with equalsIgnoreCase

        System.out.println(String.join(" of ", name, city));
    }
}

Common Mistakes

if (name == "Alice")       // ❌ Compares memory addresses
if (name.equals("Alice"))  // ✅ Compares text content
name.toUpperCase();        // ❌ Result thrown away!
name = name.toUpperCase(); // ✅ Store the new string

Pro Tips

💡 Use .equalsIgnoreCase() for user input — users might type "YES", "Yes", or "yes".

💡 Use .strip() instead of .trim() (Java 11+) — it handles Unicode whitespace properly.

💡 Use String.format() for readable string construction instead of chaining + operators.

💡 Java 15+ text blocks: Use """multi-line text""" for SQL queries, HTML, and JSON.

💡 String.join() is your friend: String.join(", ", list) is cleaner than manual loops.

📋 Quick Reference

MethodExampleResult
length()"Hello".length()5
charAt(i)"Hello".charAt(1)'e'
equals()"Hi".equals("Hi")true
substring(a,b)"Hello".substring(0,3)"Hel"
indexOf()"Hello".indexOf("ll")2
split()"a,b".split(",")["a","b"]
replace()"Hi".replace("H","B")"Bi"
trim()" Hi ".trim()"Hi"
format()String.format("%s=%d","x",5)"x=5"

🎉 Lesson Complete!

You now know how to create, compare, search, split, format, and efficiently build strings in Java! Strings appear in virtually every Java program — from parsing user input to building SQL queries to formatting log messages.

Practice quiz

What does it mean that Strings are immutable?

  • They can be changed in place
  • They are always empty
  • Once created, a String can never be changed
  • They cannot be printed

Answer: Once created, a String can never be changed. Immutable means a String never changes; methods like toUpperCase return a brand-new String.

Which is the correct way to compare two Strings' text content?

  • s1.equals(s2)
  • s1 == s2
  • s1 = s2
  • s1.compare(s2)

Answer: s1.equals(s2). Use .equals() to compare content; == compares object references.

What does "Hello, World!".length() return?

  • 12
  • 11
  • 14
  • 13

Answer: 13. Counting all characters including the comma, space, and !, the length is 13.

What does "Hello, World!".substring(7) return?

  • "World"
  • "World!"
  • ", World!"
  • "Hello, "

Answer: "World!". substring(7) returns everything from index 7 to the end: "World!".

What does name.toUpperCase(); do if you do NOT assign the result?

  • Nothing useful — the new String is discarded
  • Changes name in place
  • Throws an error
  • Returns null

Answer: Nothing useful — the new String is discarded. Strings are immutable, so the new uppercase String is thrown away unless you store it.

What does System.out.println("Score: " + 5 + 3); print?

  • Score: 8
  • Score: 5 3
  • Score: 53
  • 8

Answer: Score: 53. Left-to-right, "Score: " + 5 makes a String, then + 3 appends '3', giving "Score: 53".

Why use StringBuilder instead of += inside a large loop?

  • It is the only way to concatenate
  • += creates a new String each iteration, wasting memory
  • StringBuilder is immutable
  • It sorts the text

Answer: += creates a new String each iteration, wasting memory. Because Strings are immutable, += makes a new object every iteration; StringBuilder uses one mutable buffer.

What does "yes".equals(input) return when input is null?

  • true
  • It throws NullPointerException
  • null
  • false (no crash)

Answer: false (no crash). Putting the constant first is null-safe: it returns false instead of throwing NullPointerException.

What does "Hello".indexOf("ll") return?

  • 1
  • 2
  • 3
  • -1

Answer: 2. "ll" starts at index 2 in "Hello".

Which format specifier prints a floating-point number to 2 decimal places?

  • %d
  • %s
  • %.2f
  • %n

Answer: %.2f. %.2f formats a floating-point value with two decimal places.

Continue this course