Quiz 2

Strings in Java — Immutability, Methods, StringBuilder

2255 words
11 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Strings in Java — Immutability, Methods, StringBuilder ## 🎯 Learning Objectives By the end of this topic, you will be able to: - Explain String immutability and its performance implications - Use common String methods: `length()`, `charAt()`, `substring()`, `indexOf()`, `equals()`, `compareTo()` - Differentiate b...

Strings in Java — Immutability, Methods, StringBuilder

🎯 Learning Objectives

By the end of this topic, you will be able to:
  • Explain String immutability and its performance implications
  • Use common String methods: length(), charAt(), substring(), indexOf(), equals(), compareTo()
  • Differentiate between String, StringBuilder, and StringBuffer
  • Choose the right string class for different scenarios
  • Understand the String pool and interning

📋 Prerequisites


1. Intuition: Why Strings Are Special

1.1 What Problem Does This Solve?

Strings are the most used data type in nearly every program — names, addresses, text, commands, error messages. Java treats String with special status:
  • It's the only class with its own operator (+ for concatenation)
  • It's the only class with string literal syntax ("hello")
  • It has a dedicated string pool for memory optimization

1.2 Mental Model: An Envelope with a Photo Inside

Imagine a sealed envelope with a photo inside. You can:
  • Look at the photo (read the string)
  • Remove the photo and put a different one in (create a new string)
  • But you cannot modify the photo itself — it's permanently sealed This is immutability: once created, a String's content never changes.

2. String Immutability

2.1 What Does Immutable Mean?

java
String s = "Hello";
s = s + " World";  // Does NOT modify "Hello" — creates a NEW string
After this code:
  • The original "Hello" still exists in memory (unmodified)
  • A new string "Hello World" is created
  • s now references the new string (Diagram)

2.2 Why Immutability?

  1. Thread safety: Strings can be safely shared across threads without synchronization
  2. Caching: Hash codes can be cached (String caches its hashCode() after first computation)
  3. Security: Strings used in class loading, network connections, file paths can't be altered
  4. String pool: Immutability enables safe sharing of string literals

2.3 The Cost of Immutability

Immutability means every modification creates a new object:
java
String s = "";
for (int i = 0; i < 1000; i++) {
    s = s + i;  // Creates a NEW string each iteration — O(n²) time!
}
This loop creates 1000+ string objects and copies all previous content each time. Never do this in a loop — use StringBuilder instead.

3. The String Pool

3.1 Interning Strings

Java maintains a string pool (in the method area / heap) of unique string literals:
java
String s1 = "Hello";            // Created in pool
String s2 = "Hello";            // Reuses pool reference
String s3 = new String("Hello"); // Forces new heap object (NOT in pool)
System.out.println(s1 == s2);  // true — same object in pool
System.out.println(s1 == s3);  // false — different objects
System.out.println(s1.equals(s3));  // true — same content
(Diagram)

3.2 Explicit Interning

java
String s = new String("Hello");
String interned = s.intern();  // Returns pool reference
System.out.println(interned == "Hello");  // true

4. Common String Methods

4.1 Inspection Methods

MethodDescriptionExampleResult
length()Number of characters"Hello".length()5
charAt(i)Character at index i"Hello".charAt(1)'e'
isEmpty()Is length 0?"".isEmpty()true
indexOf(ch)First index of character"Hello".indexOf('l')2
lastIndexOf(ch)Last index of character"Hello".lastIndexOf('l')3
contains(s)Contains substring?"Hello".contains("ell")true
startsWith(prefix)Starts with prefix?"Hello".startsWith("He")true
endsWith(suffix)Ends with suffix?"Hello".endsWith("lo")true

4.2 Comparison Methods

MethodDescriptionExampleResult
equals(s)Content comparison"Hi".equals("Hi")true
equalsIgnoreCase(s)Case-insensitive"Hi".equalsIgnoreCase("hi")true
compareTo(s)Lexicographic comparison"A".compareTo("B")Negative
compareToIgnoreCase(s)Case-insensitive compare"a".compareToIgnoreCase("A")0
compareTo returns:
  • Negative if this string comes before the argument
  • Zero if they're equal
  • Positive if this string comes after
java
System.out.println("apple".compareTo("banana")); // Negative (<0)
System.out.println("hello".compareTo("hello"));   // 0
System.out.println("zebra".compareTo("apple"));   // Positive (>0)

4.3 Manipulation Methods (Return New Strings)

MethodDescriptionExampleResult
substring(start, end)Extract substring"Hello".substring(1, 4)"ell"
substring(start)Substring from start"Hello".substring(2)"llo"
concat(s)Append string"Hi".concat(" there")"Hi there"
replace(old, new)Replace characters"Hello".replace('l', 'w')"Hewwo"
toLowerCase()Convert to lowercase"Hello".toLowerCase()"hello"
toUpperCase()Convert to uppercase"Hello".toUpperCase()"HELLO"
trim()Remove leading/trailing whitespace" Hi ".trim()"Hi"
strip()Unicode-aware trim (Java 11+)" Hi ".strip()"Hi"
join(delimiter, parts)Join stringsString.join("-", "a", "b", "c")"a-b-c"

4.4 Searching Methods

MethodDescriptionExampleResult
indexOf(str)First occurrence"Hello".indexOf("ll")2
lastIndexOf(str)Last occurrence"Hello llo".lastIndexOf("ll")6
matches(regex)Regex match"abc123".matches("\\w+")true
split(regex)Split by delimiter"a,b,c".split(",")["a","b","c"]

4.5 Converting to/from Arrays

java
// String → char array
String s = "Hello";
char[] chars = s.toCharArray();
// String → byte array (for encoding)
byte[] bytes = s.getBytes();  // Uses default charset
// char array → String
String t = new String(new char[]{'H', 'i'});
// String → int/parse
int num = Integer.parseInt("123");
double d = Double.parseDouble("3.14");

5. StringBuilder and StringBuffer

5.1 The Problem They Solve

String concatenation in loops is extremely inefficient:
java
// BAD — O(n²) time, creates n intermediate strings
String s = "";
for (int i = 0; i < 10000; i++) {
    s += i;  // Each += copies the entire string!
}
// GOOD — O(n) time, mutable buffer
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    sb.append(i);  // Appends without copying the whole thing
}
String result = sb.toString();

5.2 StringBuilder vs StringBuffer

FeatureStringBuilderStringBuffer
Thread safetyNot synchronized (faster)Synchronized (thread-safe)
SpeedFasterSlower (due to synchronization)
When to useSingle-threadedMulti-threaded (rare)
In practice: Use StringBuilder almost always. StringBuffer was the original Java 1.0 version; StringBuilder (Java 5+) is its faster replacement.

5.3 StringBuilder Methods

java
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");        // Append: "Hello World"
sb.insert(5, " Dear");      // Insert at index 5: "Hello Dear World"
sb.replace(6, 10, "Friend"); // Replace range: "Hello Friend World"
sb.delete(5, 7);            // Delete range: "Hello iend World"
sb.reverse();               // Reverse: "dlroW dneiF olleH"
sb.setCharAt(0, 'h');       // Set single char: "h..."
sb.length();                // Length
sb.toString();              // Convert to String

5.4 Performance Comparison

java
// Method 1: String concatenation (BAD)
long start = System.nanoTime();
String s = "";
for (int i = 0; i < 10000; i++) {
    s += i;
}
long end = System.nanoTime();
System.out.println("String: " + (end - start) / 1_000_000 + " ms");
// Method 2: StringBuilder (GOOD)
start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    sb.append(i);
}
end = System.nanoTime();
System.out.println("StringBuilder: " + (end - start) / 1_000_000 + " ms");
// Results: StringBuilder is typically 100-1000x faster for large loops!

6. String Comparison: == vs equals()

This is the #1 String mistake in Java:
java
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2);       // true (same pool reference)
System.out.println(s1 == s3);       // false (different references)
System.out.println(s1.equals(s3));  // true (same content)
// User input always creates new strings:
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();  // e.g., "Hello"
System.out.println(s1 == input);       // false! Always check equals()
System.out.println(s1.equals(input));  // true
Rule of thumb: Use .equals() for content comparison. Only use == if you intentionally want to check reference identity.

7. Java vs Python: Strings

FeatureJavaPython
ImmutableYesYes
String poolYes (literals)Yes (interned automatically)
Concatenation+ operator+ operator
RepetitionNo operator"a" * 3"aaa"
FormatString.format() or %sf"{name}" or .format()
StringBuilderStringBuilder, StringBufferNot needed (strings immutable but join is fast)
Substrings.substring(1, 4)s[1:4] (slice)
Multi-line""" not supported (use +)"""triple quotes"""
RegexString.matches(), Patternre.match(), re.search()
Character accesss.charAt(1)s[1]

8. Common Pitfalls

Pitfall 1: Using == for String Comparison

java
Scanner sc = new Scanner(System.in);
String input = sc.next();  // User types "yes"
if (input == "yes") {  // ALWAYS false!
    System.out.println("You said yes");
}
Why: sc.next() returns a new String object, different from the literal "yes". Fix: if (input.equals("yes")) or if ("yes".equals(input)) (null-safe).

Pitfall 2: String Concatenation in Loops

java
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i;  // O(n²) time, memory hog
}
Why: Each += creates a new String, copying all previous content. Fix: Use StringBuilder:
java
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
String result = sb.toString();

Pitfall 3: substring Index Confusion

java
String s = "Hello";
System.out.println(s.substring(1, 4));  // "ell" (NOT indices 1-4!)
Why: substring(1, 4) goes from index 1 inclusive to index 4 exclusive. Fix: Remember: substring(beginIndex, endIndex) — endIndex is exclusive.

Pitfall 4: Forgetting That Strings Are Immutable

java
String s = "Hello";
s.toUpperCase();  // Returns NEW string, doesn't modify s!
System.out.println(s);  // "Hello" — unchanged!
Why: All String manipulation methods return a new string; the original is unchanged. Fix: s = s.toUpperCase(); (assign result back).

Pitfall 5: Using + Inside StringBuilder

java
StringBuilder sb = new StringBuilder();
sb.append("Hello " + name);  // Still creates intermediate String!
Why: The + concatenation happens BEFORE append(), defeating the purpose. Fix: sb.append("Hello ").append(name);

9. Practice Questions

Q1: What is the output?
java
String s1 = "Java";
String s2 = "Java";
String s3 = new String("Java");
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
Answer:
pseudo
true
false
true
s1 == s2: Both are literals, same pool reference → true. s1 == s3: s3 is a new String object → false. s1.equals(s3): Content is identical → true. Q2: Why is this code inefficient? Rewrite it.
java
String csv = "";
for (String s : items) {
    csv = csv + s + ",";
}
Answer: Each iteration creates 2-3 new String objects (the + creates intermediate strings). For large items, this is O(n²).
Fix with StringBuilder:
java
StringBuilder sb = new StringBuilder();
for (String s : items) {
    sb.append(s).append(",");
}
String csv = sb.toString();
// Or use: String csv = String.join(",", items);
Q3: What is the output?
java
String s = "Hello";
s.concat(" World");
System.out.println(s);
Answer: Hello
concat() returns a new string but doesn't modify the original. Since the result isn't assigned, it's discarded. s still references "Hello". The correct way: s = s.concat(" World"); Q4: What does this code return?
java
String s = "banana";
System.out.println(s.indexOf('a'));
System.out.println(s.lastIndexOf('a'));
System.out.println(s.indexOf("na"));
System.out.println(s.indexOf('x'));
Answer:
pseudo
1
5
2
-1
  • indexOf('a'): first 'a' is at index 1
  • lastIndexOf('a'): last 'a' is at index 5
  • indexOf("na"): "na" starts at index 2
  • indexOf('x'): not found → -1 Q5: What is the difference between StringBuilder and StringBuffer?
Answer: StringBuffer is synchronized (thread-safe) while StringBuilder is not. In single-threaded code, StringBuilder is faster (no synchronization overhead). Use StringBuilder unless you need thread safety, which is rare for string manipulation.
Both have the same API (append, insert, delete, reverse, etc.) and both are mutable. Q6: What is the output?
java
String s = "Hello World";
System.out.println(s.substring(6));
System.out.println(s.substring(0, 5));
Answer:
pseudo
World
Hello
  • substring(6): from index 6 to end → "World"
  • substring(0, 5): from index 0 inclusive to 5 exclusive → "Hello"
Remember: substring(beginIndex) or substring(beginIndex, endIndex) where endIndex is exclusive. Q7: How does the intern() method work?
Answer: intern() checks the string pool: if a matching string exists in the pool, it returns the pool reference. Otherwise, it adds the string to the pool and returns its reference.
java
String s1 = new String("Hello");
String s2 = s1.intern();  // Returns pool reference
String s3 = "Hello";
System.out.println(s2 == s3);  // true — both are pool references
System.out.println(s1 == s3);  // false — s1 is heap, s3 is pool
Q8: What is the output?
java
System.out.println("Hello".compareTo("Hello"));
System.out.println("A".compareTo("B"));
System.out.println("B".compareTo("A"));
System.out.println("hello".compareTo("Hello"));
Answer:
pseudo
0
-1
1
32
  • Equal strings return 0
  • "A" < "B" → negative (-1)
  • "B" > "A" → positive (1)
  • "hello" > "Hello" because lowercase letters have higher Unicode values Q9: Write code to reverse a string in Java.
Answer:
java
// Method 1: StringBuilder
String original = "Hello";
String reversed = new StringBuilder(original).reverse().toString();
System.out.println(reversed);  // "olleH"

// Method 2: Manual loop
public static String reverse(String s) {
    char[] chars = s.toCharArray();
    int left = 0, right = chars.length - 1;
    while (left < right) {
        char temp = chars[left];
        chars[left] = chars[right];
        chars[right] = temp;
        left++;
        right--;
    }
    return new String(chars);
}
Q10: What is the output of this code and why?
java
String path = "C:\\Users\\John\\file.txt";
System.out.println(path);
Answer: C:\Users\John\file.txt
In Java strings, \\ is an escape sequence representing a single backslash character \. Each \\ in the literal produces one \ in the actual string. This is because \ is the escape character, so to include a literal \, you double it.

📐 Key Concepts

ConceptKey Points
ImmutabilityStrings cannot be changed; every modification creates a new string
String poolLiterals are stored in a pool for reuse; intern() accesses the pool
Content comparisonAlways use .equals(), never ==
StringBuilderMutable; use for concatenation in loops
Common methodslength(), charAt(), substring(), indexOf(), split(), trim()
ConversionstoCharArray(), Integer.parseInt(), String.valueOf()
PerformanceStringBuilder is 100-1000x faster than + in loops

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.