Topic 9 of 28 · Android Native Developer

Topic 9 : Strings in Java

Lesson TL;DRTopic 9: Strings in Java 📖 5 min read · 🎯 intermediate · 🧭 Prerequisites: inheritanceinjava, fragmentsintentsintentfilters Why this matters Here's the thing — almost everything your Android app sho...
5 min read·intermediate·java · strings · stringbuilder · stringbuffer

Topic 9: Strings in Java

📖 5 min read · 🎯 intermediate · 🧭 Prerequisites: inheritance-in-java, fragments-intents-intent-filters

Why this matters

Here's the thing — almost everything your Android app shows to the user is text. Button labels, error messages, names, addresses, search queries — all of it is a String. And when you're just starting out, it looks simple: just put some words in quotes and move on. But Java has three different tools for working with text — String, StringBuilder, and StringBuffer — and picking the wrong one can quietly slow your app down or give you results you didn't expect. Once you understand why they exist, a lot of Java code will start making more sense.

What You'll Learn

  • Create String objects using literals and the new keyword
  • Use the most important built-in String methods (length, charAt, substring, replace, equals, toUpperCase, trim, and more)
  • Understand why String objects are immutable and what that means in practice
  • Choose between StringBuilder and StringBuffer for mutable text manipulation

The Analogy

Think of a Java String as a laminated ID card — the text printed on it is fixed the moment it is made. If you need a corrected card, you don't erase the old one; you print a brand-new card and hand that out instead. The original card sits unchanged in a drawer. StringBuilder, by contrast, is a whiteboard: you can write, erase, and rewrite as many times as you like without ever touching a new board. StringBuffer is that same whiteboard, but mounted behind a locked cabinet — only one person can write at a time, making it safe for a busy shared office but a bit slower to access.

Chapter 1: Creating Strings

Java gives you two ways to bring a String into existence.

String literals — the most common form. The JVM stores literals in a special pool and may reuse the same object if the same text appears again, saving memory.

The new keyword — forces the JVM to allocate a brand-new object on the heap, bypassing the pool. Rarely needed, but worth knowing it exists.

public class StringDemo {
    public static void main(String[] args) {
        // Creating strings using string literals
        String greeting = "Hello, Full Stack World!";

        // Creating strings using the new keyword
        String message = new String("Welcome to the adventure of Strings!");

        // Display the strings
        System.out.println(greeting);
        System.out.println(message);
    }
}

Output:

Hello, Full Stack World!
Welcome to the adventure of Strings!

Chapter 2: String Methods

String ships with a rich set of built-in methods. The eight you will reach for most often are:

  1. length() — number of characters in the string
  2. Concatenation (+ operator) — joins two strings into one new string
  3. charAt(int index) — returns the character at a zero-based position
  4. substring(int start, int end) — extracts characters from start (inclusive) to end (exclusive)
  5. replace(CharSequence target, CharSequence replacement) — swaps every occurrence of target for replacement
  6. equals(Object other) — compares content, not reference (always prefer over ==)
  7. toUpperCase() / toLowerCase() — returns a case-converted copy
  8. trim() — removes leading and trailing whitespace

Here is all eight in a single demo:

public class StringMethodsDemo {
    public static void main(String[] args) {
        String str = " Full Stack World ";

        // Length of the string
        System.out.println("Length: " + str.length());

        // Concatenation
        String greeting = "Hello," + str.trim();
        System.out.println("Greeting: " + greeting);

        // Character access
        char firstChar = str.charAt(1);
        System.out.println("First character: " + firstChar);

        // Substring
        String world = str.substring(6, 11);
        System.out.println("Substring: " + world);

        // Replace
        String replacedStr = str.replace("Stack", "Developer");
        System.out.println("Replaced: " + replacedStr);

        // Comparison
        boolean equals = str.equals(" Full Stack World ");
        System.out.println("Equals: " + equals);

        // Case conversion
        System.out.println("Upper case: " + str.toUpperCase());
        System.out.println("Lower case: " + str.toLowerCase());

        // Trim
        System.out.println("Trimmed: " + str.trim());
    }
}

Expected output:

Length: 18
Greeting: Hello,Full Stack World
First character: F
Substring: Stack
Replaced:  Full Developer World
Equals: true
Upper case:  FULL STACK WORLD
Lower case:  full stack world
Trimmed: Full Stack World

Chapter 3: String Immutability

Once a String object is created, its content cannot change. Every method that appears to "modify" a string — concat, replace, toUpperCase, etc. — actually returns a new String object and leaves the original untouched.

public class StringImmutability {
    public static void main(String[] args) {
        String original = "Immutable";
        String modified = original.concat(" String");

        System.out.println("Original: " + original);
        System.out.println("Modified: " + modified);
    }
}

Output:

Original: Immutable
Modified: Immutable String

original still holds "Immutable". concat produced a brand-new object stored in modified.

Why immutability matters for Android:

  • Security — a String passed to an authentication method cannot be altered mid-flight by another thread.
  • Thread safety — multiple threads can read the same String without synchronization.
  • String pool reuse — the JVM can safely hand out the same object to multiple callers, reducing heap pressure.

The downside surfaces when you build strings in a loop. Each + inside a loop allocates a fresh object. For tight loops or frequent concatenation, reach for StringBuilder instead.

Chapter 4: StringBuilder and StringBuffer

Both classes represent mutable sequences of characters — you modify the same underlying buffer rather than creating new objects.

StringBuilder

StringBuilder is not synchronized. Only one thread should use a given instance at a time, but in return you get faster performance. This is the right choice in the vast majority of Android code running on a single thread.

public class StringBuilderDemo {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Full Stack");

        sb.append(" World");
        System.out.println(sb.toString()); // Full Stack World

        sb.insert(5, " Developer");
        System.out.println(sb.toString()); // Full  Developer Stack World

        sb.replace(5, 14, " Engineer");
        System.out.println(sb.toString()); // Full  Engineer Stack World

        sb.delete(5, 14);
        System.out.println(sb.toString()); // Full Stack World
    }
}

Key StringBuilder methods:

MethodWhat it does
append(String s)Adds s to the end of the buffer
insert(int offset, String s)Inserts s at position offset
replace(int start, int end, String s)Replaces characters from start to end with s
delete(int start, int end)Removes characters from start to end
toString()Converts the buffer to an immutable String

StringBuffer

StringBuffer is synchronized — every method is thread-safe. Use it only when multiple threads genuinely share the same buffer. The synchronization overhead makes it slower than StringBuilder for single-threaded use.

public class StringBufferDemo {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Full Stack");

        sb.append(" World");
        System.out.println(sb.toString()); // Full Stack World

        sb.insert(5, " Developer");
        System.out.println(sb.toString()); // Full  Developer Stack World

        sb.replace(5, 14, " Engineer");
        System.out.println(sb.toString()); // Full  Engineer Stack World

        sb.delete(5, 14);
        System.out.println(sb.toString()); // Full Stack World
    }
}

The API is identical to StringBuilder; the only difference is thread-safety behaviour under the hood.

Quick comparison

String          → immutable, thread-safe, great for fixed text
StringBuilder   → mutable, NOT thread-safe, best performance for single thread
StringBuffer    → mutable, thread-safe, use only with shared mutable state across threads
flowchart TD
    A[Need a string?] --> B{Will it change?}
    B -- No --> C[String literal or new String]
    B -- Yes --> D{Shared across threads?}
    D -- No --> E[StringBuilder]
    D -- Yes --> F[StringBuffer]

🧪 Try It Yourself

Task: Write a program that takes the sentence " Android Development is Powerful " and, using only built-in String methods, prints:

  1. The trimmed version
  2. The length of the trimmed version
  3. The sentence in all caps
  4. The word "Powerful" replaced with "Awesome"
  5. The character at index 7 of the trimmed string

Success criterion: Your console output should look like this:

Trimmed: Android Development is Powerful
Length: 35
Upper: ANDROID DEVELOPMENT IS POWERFUL
Replaced: Android Development is Awesome
Char at 7: D

Starter snippet:

public class StringExercise {
    public static void main(String[] args) {
        String sentence = "  Android Development is Powerful  ";

        String trimmed = sentence.trim();
        // 1. Print trimmed
        // 2. Print trimmed.length()
        // 3. Print trimmed.toUpperCase()
        // 4. Print trimmed.replace("Powerful", "Awesome")
        // 5. Print trimmed.charAt(7)
    }
}

🔍 Checkpoint Quiz

Q1. Why are Java String objects immutable, and what is one practical benefit of that design?

Q2. Given the following code, what does it print?

String s = "Hello World";
System.out.println(s.substring(6, 11));

A) Hello B) World C) World! D) o Wor

Q3. A colleague writes this loop to build a comma-separated list of 10,000 IDs:

String result = "";
for (int id : idList) {
    result = result + id + ",";
}

What is the problem, and how would you fix it?

Q4. You are writing an Android background service where two worker threads append log lines to the same buffer. Which class should you use — StringBuilder or StringBuffer — and why?

A1. String objects are immutable because once created their internal character array cannot change. A key benefit: immutability makes String inherently thread-safe — multiple threads can read the same object without any synchronization.

A2. B) Worldsubstring(6, 11) extracts characters at indices 6, 7, 8, 9, 10 (the end index is exclusive), which spells World.

A3. Each iteration of the loop creates a brand-new String object for result, throwing away the old one. For 10,000 iterations that means 10,000 allocations and copies, causing significant heap churn. Fix: use a StringBuilder and call append() inside the loop, then call toString() once at the end.

A4. StringBuffer — because it is synchronized. When two threads share the same mutable buffer, unsynchronized writes (as with StringBuilder) can interleave and corrupt the data. StringBuffer's method-level locks prevent that.

🪞 Recap

  • Java String is an immutable sequence of characters; every "modification" produces a new object.
  • The eight essential String methods — length, charAt, substring, replace, equals, toUpperCase, toLowerCase, trim — cover the majority of text operations.
  • Immutability makes String thread-safe and enables JVM string-pool optimizations, but it is inefficient for repeated concatenation.
  • StringBuilder is the go-to for single-threaded mutable string building; it is faster because it skips synchronization.
  • StringBuffer mirrors StringBuilder's API but adds thread safety through synchronized methods — use it only when threads genuinely share the buffer.

📚 Further Reading

Like this topic? It’s one of 28 in Android Native Developer.

Block your seat for ₹2,500 and join the next cohort.