Java String Immutability - නොනැසී පවතින Strings | SC Guide

ආයුබෝවන් හැමෝටම! Java String Immutability: එය කුමක්ද සහ එය වැදගත් වන්නේ ඇයි?
අද අපි Java වල තියෙන ගොඩක් වැදගත්, හැබැයි සමහරුන්ට අවුල් වෙන "String Immutability" කියන සංකල්පය ගැන කතා කරමු. ඔයා Java programmer කෙනෙක් නම්, මේක දැනගෙන ඉන්න එක අත්යවශ්යයි. මොකද, `String` කියන්නේ අපි හැමදාම වගේ පාවිච්චි කරන data type එකක්.
"Immutable" කියන්නේ මොකක්ද? ඒක `String` වලට විතරද? ඇයි `String` immutable වෙන්නේ? මේ හැම ප්රශ්නයකටම උත්තර මේ ලිපියෙන් හොයාගන්න පුළුවන්. මේක ඔයාගේ Java programming දැනුමට ලොකු වටිනාකමක් එකතු කරයි.
1. Immutable කියන්නේ මොකක්ද? (What is Immutability?)
සරලවම කිව්වොත්, "immutable" කියන්නේ වරක් හදපු object එකක state එක ආයෙ වෙනස් කරන්න බැරිවීමයි. ඒ කියන්නේ, ඔයා `String` object එකක් හැදුවම, ඒක ඇතුළේ තියෙන characters ටික (data) කවදාවත් වෙනස් කරන්න බෑ.
මේක තේරුම් ගන්න පහසුම උදාහරණය තමයි "ලියපු ඔප්පුවක්" වගේ. ඔප්පුවක් ලියල ඉවර වුනාම ඒකෙ තියෙන දේවල් වෙනස් කරන්න බෑ, වෙනස් කරන්න ඕන නම් අලුත් ඔප්පුවක් ලියන්න වෙනවා. Java වල `String` ක්රියාත්මක වෙන්නේ ඒ විදියට තමයි.
Java වල `String` වගේම `Integer`, `Long`, `Boolean` වගේ `Wrapper` classes ත් `immutable` තමයි. හැබැයි, `mutable` object එකක් කියන්නේ හදපු object එකේ `state` එක පස්සේ වෙනස් කරන්න පුළුවන් වීම. උදාහරණයක් විදියට `ArrayList`, `Date` class වගේ ඒවා.
ප්රායෝගික උදාහරණයක් (Practical Example):
public class ImmutabilityExample {
public static void main(String[] args) {
// Immutable String Example
String myString = "Hello"; // myString points to a String object "Hello"
System.out.println("Original String: " + myString); // Output: Original String: Hello
System.out.println("Hash code of original String: " + System.identityHashCode(myString)); // Unique hash code
myString = myString + " World"; // A *new* String object "Hello World" is created.
// 'myString' now points to this new object.
// The original "Hello" object remains unchanged in memory.
System.out.println("Modified String (new object created): " + myString); // Output: Modified String (new object created): Hello World
System.out.println("Hash code of modified String: " + System.identityHashCode(myString)); // Different unique hash code
System.out.println("\n---
");
// Mutable Example (using ArrayList)
java.util.ArrayList<String> myList = new java.util.ArrayList<>();
System.out.println("Original ArrayList: " + myList); // Output: Original ArrayList: []
System.out.println("Hash code of original ArrayList: " + System.identityHashCode(myList)); // Unique hash code
myList.add("Apple"); // The *same* ArrayList object is modified.
myList.add("Banana");
System.out.println("Modified ArrayList (same object modified): " + myList); // Output: Modified ArrayList (same object modified): [Apple, Banana]
System.out.println("Hash code of modified ArrayList: " + System.identityHashCode(myList)); // Same unique hash code
}
}
මේ උදාහරණයෙන් පේනවා, `String` එක වෙනස් කරනවා වගේ පෙනුනත්, ඇත්තටම වෙන්නේ අලුත් `String` object එකක් හැදිලා, variable එක ඒ අලුත් object එකට point කරන එකයි. ඒත් `ArrayList` එක modify කරනකොට, ඒක සිදුවෙන්නේ මුල් `object` එකේමයි.
2. ඇයි Java Strings Immutable වෙන්නේ? (Why are Java Strings Immutable?)
මේක තමයි ගොඩක් වැදගත් කොටස. `String` immutable වෙන්න ප්රධාන හේතු කීපයක් තියෙනවා:
2.1. Security (ආරක්ෂාව)
Java Strings ගොඩක් වෙලාවට username, password, network connection details, database URLs, file paths වගේ sensitive දේවල් store කරන්න පාවිච්චි කරනවා. `String` mutable නම්, මේ වගේ sensitive information එකක් reference කරන variable එකක් අනිත් code එකකින් වෙනස් කරන්න පුළුවන්. ඒක ආරක්ෂාවට ලොකු තර්ජනයක්. Immutable නිසා, ඔයාට පුළුවන් විශ්වාස කරන්න ඒ `String` එකේ තියෙන data එක කවදාවත් වෙනස් වෙන්නේ නෑ කියලා. මේකෙන් ඔයාගේ application එකට ලොකු ආරක්ෂාවක් ලැබෙනවා.
2.2. Thread Safety (Thread ආරක්ෂාව)
Multi-threaded environments වල (එකම වෙලාවේ code lines කිහිපයක් execute කරන අවස්ථා), එකම `String` object එකකට threads ගොඩක් access කරනකොට, mutable object එකක් නම් "race conditions" වගේ අවුල් ඇති වෙන්න පුළුවන්. Immutable නිසා, එකම `String` එකට කී දෙනෙක් access කලත්, ඒකේ value එක වෙනස් වෙන්නේ නැති නිසා, "synchronization" issues ගැන හිතන්න ඕනේ නෑ. ඒක "thread safe" වෙනවා. මේකෙන් concurrent programming පහසු වෙනවා.
2.3. Performance & String Pool (කාර්ය සාධනය සහ String Pool)
Java JVM එකේ "String Literal Pool" කියලා විශේෂ මතක ඉඩක් තියෙනවා. `String s = "hello";` වගේ "String literals" හදනකොට, JVM එක බලනවා "String pool" එකේ "hello" කියන String එක කලින් තියෙනවද කියලා. තියෙනවා නම්, අලුතින් `String` එකක් හදන්නේ නැතුව ඒ තියෙන එකම reference කරනවා. මේ "optimization" එක වැඩ කරන්නේ `String` immutable නිසා. "hello" කියන `String` එක mutable නම්, pool එකේ තියෙන "hello" එක වෙනස් කරන්න පුළුවන් වුණොත්, ඒක පාවිච්චි කරන අනිත් හැම තැනකම අවුල් ඇතිවෙනවා. Immutability මේ "caching" එකට උදව් කරනවා, ඒ වගේම memory consumption එකත් අඩු කරනවා.
public class StringPoolExample {
public static void main(String[] args) {
String s1 = "java";
String s2 = "java";
String s3 = new String("java");
// s1 and s2 will refer to the same object in the String Pool
System.out.println("s1 == s2: " + (s1 == s2)); // Output: true
System.out.println("Hash code of s1: " + System.identityHashCode(s1));
System.out.println("Hash code of s2: " + System.identityHashCode(s2));
// s3 creates a new object in the heap, not in the pool initially
System.out.println("s1 == s3: " + (s1 == s3)); // Output: false
System.out.println("Hash code of s3: " + System.identityHashCode(s3));
}
}
මේකෙන් පේනවා `String` literals දෙකක් එකම object එකට point කරනවා. Immutability නොතිබුණා නම් මේක භයානක වෙන්න තිබ්බා!
2.4. Hashing (Hash කිරීම)
`String` objects ගොඩක් වෙලාවට `HashMap`, `HashSet` වගේ `Collection` objects වල `keys` විදියට පාවිච්චි කරනවා. `HashMap` එකක් `key` එකක `hash code` එක මත රඳා පවතිනවා. `String` එක mutable නම්, `HashMap` එකට `key` එකක් විදියට දාලා පස්සේ `key` එකේ value එක වෙනස් කලොත්, `hash code` එකත් වෙනස් වෙලා, `HashMap` එකට ඒ entry එක හොයාගන්න බැරිවෙන්න පුළුවන්. Immutable නිසා `hash code` එකත් fix වෙනවා, ඒ නිසා `HashMap` වගේ දේවල් වලට `String` safe `key` එකක් විදියට පාවිච්චි කරන්න පුළුවන්.
3. ප්රායෝගික බලපෑම් සහ උදාහරණ (Practical Implications and Examples)
අපි කලින් කතා කරා වගේ, `String` එකක් වෙනස් කරනවා වගේ පෙනුනත් ඇත්තටම වෙන්නේ අලුත් object එකක් හැදෙන එක. මේකේ බලපෑම තමයි, ඔයා ගොඩක් `String` operations කරනකොට (e.g., loops ඇතුලේ `String` concatenate කරනවා නම්), `String` immutable නිසා හැම පාරම අලුත් object එකක් හැදිලා "memory" සහ "performance" ප්රශ්න ඇතිවෙන්න පුළුවන්.
3.1. String Concatenation Issue:
public class StringConcatenationIssue {
public static void main(String[] args) {
String result = "";
long startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) {
result = result + i; // Each concatenation creates a new String object
}
long endTime = System.nanoTime();
long duration = (endTime - startTime) / 1_000_000; // milliseconds
System.out.println("Time taken by String concatenation: " + duration + " ms");
// You will notice this takes longer for larger iterations
}
}
මේ වගේ තැන් වලට `StringBuilder` සහ `StringBuffer` පාවිච්චි කරන්න පුළුවන්. මේවා `mutable` Strings. මේවා `String` operations ගොඩක් කරනකොට වඩාත් "memory efficient" සහ "performance" වලට හොඳයි.
3.2. Mutable Alternatives: `StringBuilder` and `StringBuffer`
- `StringBuilder`: Single-threaded environments වලදී පාවිච්චි කරන්න. මේක `StringBuffer` වලට වඩා වේගවත්.
- `StringBuffer`: Multi-threaded environments වලදී පාවිච්චි කරන්න. මේක `synchronized` නිසා `thread safe` වේ. (ඉස්සර කාලේ ගොඩක් පාවිච්චි වුනත්, දැන් `StringBuilder` සහ `CompletableFuture` වගේ දේවල් නිසා `StringBuffer` පාවිච්චිය අඩුයි)
public class StringBuilderExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
System.out.println("StringBuilder before append: " + sb); // Output: Hello
System.out.println("Hash code of StringBuilder: " + System.identityHashCode(sb)); // Unique hash code
sb.append(" World"); // Modifies the *same* StringBuilder object
System.out.println("StringBuilder after append: " + sb); // Output: Hello World
System.out.println("Hash code of StringBuilder after append: " + System.identityHashCode(sb)); // Same unique hash code
System.out.println("\n---
");
// Performance comparison with StringBuilder
StringBuilder resultBuilder = new StringBuilder();
long startTimeBuilder = System.nanoTime();
for (int i = 0; i < 1000; i++) {
resultBuilder.append(i);
}
long endTimeBuilder = System.nanoTime();
long durationBuilder = (endTimeBuilder - startTimeBuilder) / 1_000_000; // milliseconds
System.out.println("Time taken by StringBuilder: " + durationBuilder + " ms");
// You will notice this is significantly faster than String concatenation
}
}
අවසන් වචන (Conclusion)
ඉතින්, `Java String Immutability` කියන්නේ `String` object එකක් හැදුවට පස්සේ ඒක වෙනස් කරන්න බෑ කියන එක. මේක `Security`, `Thread Safety`, `Performance (String Pool)`, සහ `Hashing` වගේ දේවල් වලට ගොඩක් වැදගත් වෙනවා. අපිට `String` එකක් වෙනස් කරන්න ඕන වුනාම, ඇත්තටම අලුත් `String` object එකක් තමයි හැදෙන්නේ.
ගොඩක් `String` operations කරනකොට (විශේෂයෙන්ම loops ඇතුලේ) `StringBuilder` හෝ `StringBuffer` පාවිච්චි කරන එක "memory efficient" සහ "performance" වලට හොඳයි. මේක තේරුම් ගන්න එක ඔයාගේ Java programming skill set එකට ලොකු වාසියක්.
මේ ගැන ඔයාලගේ අත්දැකීම් මොනවද? නැත්නම් මොනවා හරි ප්රශ්න තියෙනවා නම් පහලින් `comment` එකක් දාගෙන යන්න! මේ ලිපිය ඔයාට ප්රයෝජනවත් වුණා නම්, අනිත් අයටත් දැනගන්න share කරන්න. ඊළඟ ලිපියකින් හමුවෙමු!