javaintermediate

String Pool and Interning

Understand Java string pooling: intern(), identity vs equality, memory optimization, and common pitfalls.

java
public class StringPoolDemo {

    public static void main(String[] args) {
        // String literals are interned automatically
        String a = "hello";
        String b = "hello";
        System.out.println(a == b);        // true — same pool reference
        System.out.println(a.equals(b));   // true

        // new String() creates a new object
        String c = new String("hello");
        System.out.println(a == c);        // false — different object
        System.out.println(a.equals(c));   // true — same content

        // intern() returns pool reference
        String d = c.intern();
        System.out.println(a == d);        // true — now same reference

        // Concatenation at compile time
        String e = "hel" + "lo";
        System.out.println(a == e);        // true — compiler optimized

        // Runtime concatenation — NOT interned
        String part = "lo";
        String f = "hel" + part;
        System.out.println(a == f);        // false
        System.out.println(a == f.intern()); // true

        // Practical use: deduplication for memory savings
        System.out.println("\n--- Memory Optimization Demo ---");
        deduplicationDemo();

        // Common pitfall: == vs .equals()
        System.out.println("\n--- Pitfalls ---");
        pitfalls();
    }

    // Dedup large datasets using intern() or a custom pool
    static void deduplicationDemo() {
        // Custom dedup pool (preferred over intern() for large data)
        java.util.Map<String, String> pool = new java.util.HashMap<>();

        String[] rawData = { "USA", "UK", "USA", "USA", "UK", "IN", "USA" };
        String[] deduped = new String[rawData.length];

        for (int i = 0; i < rawData.length; i++) {
            deduped[i] = pool.computeIfAbsent(rawData[i], k -> k);
        }

        // All "USA" entries point to the same object
        System.out.println(deduped[0] == deduped[2]); // true
        System.out.println(deduped[0] == deduped[3]); // true
        System.out.println("Pool size: " + pool.size()); // 3
    }

    static void pitfalls() {
        // NEVER use == for string comparison in business logic
        String userInput = new java.util.Scanner(System.in).toString();
        // BAD:  if (userInput == "admin")
        // GOOD: if ("admin".equals(userInput))  — null-safe!

        // Integer.toString() is NOT interned
        String n1 = Integer.toString(42);
        String n2 = Integer.toString(42);
        System.out.println(n1 == n2);       // false
        System.out.println(n1.equals(n2));   // true

        // substring() in modern Java creates a new backing array
        String full = "Hello, World!";
        String sub = full.substring(0, 5);
        System.out.println(sub);            // Hello
        System.out.println(full == sub);    // false
    }
}

Use Cases

  • Memory optimization for repeated string values
  • Understanding Java string comparison behavior
  • Data deduplication in ETL pipelines

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.