Leverage Immutability for Hashcode Caching in Collections
The immutability of Strings makes them ideal for use as keys in hash-based collections like HashMap and HashSet. Because a String's value never changes, its hashCode() can be computed once and cached. Subsequent calls to hashCode() will return the cached value, leading to significant performance improvements, especially when Strings are frequently used as keys.
If Strings were mutable, their hash code could change after being inserted into a HashMap, making it impossible to retrieve the object using the original hash code.
Let's add code to ImmutableStringDemo.java to demonstrate String usage in a HashMap.
Add the following code to the main method of your ImmutableStringDemo.java file, after the thread safety demonstration:
// ~/project/ImmutableStringDemo.java
import java.util.HashMap; // Ensure this import is at the top of your file
public class ImmutableStringDemo {
private static final String SECURE_PASSWORD = "MySecurePassword123";
static class ThreadSafeTask implements Runnable {
private final String password;
public ThreadSafeTask(String password) {
this.password = password;
}
@Override
public void run() {
System.out.println("Thread " + Thread.currentThread().getName() + " accessing password: " + password);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public static void main(String[] args) {
// ... (previous code for name, str1, str2, str3, and thread safety remains here) ...
String name = "LabexUser";
System.out.println("Initial name: " + name);
String str1 = "Hello";
String str2 = "Hello";
System.out.println("str1: " + str1);
System.out.println("str2: " + str2);
System.out.println("str1 == str2: " + (str1 == str2));
String str3 = new String("Hello");
System.out.println("str3: " + str3);
System.out.println("str1 == str3: " + (str1 == str3));
System.out.println("\n--- Demonstrating Security and Thread Safety ---");
System.out.println("Secure Password: " + SECURE_PASSWORD);
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(new ThreadSafeTask(SECURE_PASSWORD), "Thread-" + (i + 1));
thread.start();
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("\n--- Demonstrating Hashcode Caching ---");
HashMap<String, Integer> studentScores = new HashMap<>();
String studentName1 = "Alice";
String studentName2 = "Bob";
String studentName3 = "Alice"; // This will refer to the same "Alice" in the String pool
studentScores.put(studentName1, 95);
studentScores.put(studentName2, 88);
studentScores.put(studentName3, 92); // This will update the value for "Alice"
System.out.println("Student Scores: " + studentScores);
System.out.println("Alice's score: " + studentScores.get("Alice"));
System.out.println("Bob's score: " + studentScores.get("Bob"));
// Demonstrate that even if we try to "change" a String, a new one is created
String originalString = "Java";
System.out.println("Original String: " + originalString + ", HashCode: " + originalString.hashCode());
String modifiedString = originalString.concat(" Programming"); // Creates a new String
System.out.println("Modified String: " + modifiedString + ", HashCode: " + modifiedString.hashCode());
System.out.println("Original String (after concat): " + originalString + ", HashCode: " + originalString.hashCode());
}
}
Save the file. Then, compile and run the program again:
javac ImmutableStringDemo.java
java ImmutableStringDemo
You should see output similar to this, including the HashMap and hashcode demonstrations:
Initial name: LabexUser
str1: Hello
str2: Hello
str1 == str2: true
str3: Hello
str1 == str3: false
--- Demonstrating Security and Thread Safety ---
Secure Password: MySecurePassword123
Thread Thread-1 accessing password: MySecurePassword123
Thread Thread-2 accessing password: MySecurePassword123
Thread Thread-3 accessing password: MySecurePassword123
--- Demonstrating Hashcode Caching ---
Student Scores: {Bob=88, Alice=92}
Alice's score: 92
Bob's score: 88
Original String: Java, HashCode: 2301506
Modified String: Java Programming, HashCode: -1479700901
Original String (after concat): Java, HashCode: 2301506
Notice how originalString's hash code remains the same even after concat is called, because concat returns a new String object, leaving the original untouched.