String, StringBuilder vs StringBuffer
ההבדל המרכזי בין String, StringBuilder ו־StringBuffer ב־Java קשור לשאלה האם המחרוזת ניתנת לשינוי והאם היא בטוחה לשימוש ב Thread-Safe.
למידע נוסף על Immutable מול Mutable ניתן לקרוא כאן: Java immutable objects
String
מחלקת String היא Immutable (בלתי ניתנת לשינוי). מרגע שנוצר אובייקט מסוג String בזיכרון, אי אפשר לשנות את תוכנו לעולם. כל פעולה שנראית כאילו משנה את המחרוזת (כמו חיבור מחרוזות עם +) מייצרת למעשה אובייקט חדש לגמרי ב־Heap.
ניהול זיכרון ו־String Pool:
מחרוזות שנוצרות כליטרל (למשל: ;"String s = "Hello) נשמרות באזור מיוחד ב־Heap שנקרא String Pool , במטרה לחסוך מקום ולמחזר מחרוזות זהות. ניתן לראות הרחבה על נושא זה < במאמר על string pool באתר
אם מחברים מחרוזות בלולאה באמצעות +, נוצרים המון אובייקטים זמניים ב־Heap שמעמיסים על ה־Garbage Collector (GC) ופוגעים דרמטית בביצועים.
מתי להשתמש? כאשר מדובר בטקסטים קבועים שלא משתנים תדיר, או כשנרצה לנצל את ה־String Pool.
2. StringBuilder (גמישות וביצועים גבוהים)
מחלקת StringBuilder היא Mutable (ניתנת לשינוי). היא נועדה בדיוק כדי לפתור את בעיית הביצועים של חיבור מחרוזות מרובות.
ניהול זיכרון:
האובייקט שומר מערך פנימי (Buffer) ב־Heap. כאשר משנים את המחרוזת (למשל באמצעות .()append), התוכן נוסף לאותו אזור זיכרון קיים מבלי לייצר אובייקטים חדשים ב־Heap (כל עוד יש מקום פנוי במערך; אם צריך, הוא מקצה מערך חדש וגדול יותר מאחורי הקלעים).
Thread Safety:
היא אינה מסונכרנת (Not Thread-Safe). משמעות הדבר היא ששני Threads שונים לא יכולים לעבוד עליה בו זמנית, אחרת ייווצרו בעיות בנתונים.
יתרון מרכזי: מהירות עצומה ויעילות גבוהה בניהול זיכרון לעומת String.
מתי להשתמש? ברוב המקרים שבהם נרצה לבנות מחרוזות ארוכות או לבצע שינויים מרובים בתוך מתודה יחידה (Single-Threaded).
3. StringBuffer (הגרסה הבטוחה ל multi Thread )
מחלקת StringBuffer דומה לחלוטין ל־StringBuilder היא גם Mutable (ניתנת לשינוי) ועובדת עם מערך פנימי ב־Heap.
ההבדל הקריטי סנכרון (Thread Safety):
כל המתודות המרכזיות ב־StringBuffer מוגדרות כ־synchronized. כלומר, היא בטוחה לחלוטין לשימוש בסביבה Multi-threaded, שבה מספר thread ניגשים לאותה מחרוזת במקביל.
המחיר בביצועים:
מנגנון הנעילה והשחרור (Synchronization overhead) הופך אותה לאיטית יותר בהשוואה ל־StringBuilder.
מתי להשתמש? רק כאשר יש צורך מוכח בשיתוף אותו אובייקט מחרוזת בין מספר thread שונים במקביל (כיום השימוש בה נדיר יחסית, שכן ברוב המוחלט של המקרים בקוד מודרני מעדיפים את StringBuilder).
טבלת השוואה טכנית
| תכונה | String | StringBuilder | StringBuffer |
|---|---|---|---|
| מוטביליות (Mutability) | אי־מוטבילי (Immutable) | מוטבילי (Mutable) | מוטבילי (Mutable) |
| Thread-Safe | כן (כי אי אפשר לשנות אותו) | לא (Not Thread-Safe) | כן (Thread-Safe / Synchronized) |
| ביצועים בשינויים מרובים | גרועים (יוצר הרבה אובייקטים ב־Heap) | מהירים ויעילים ביותר | איטי יותר מ־StringBuilder בגלל הסנכרון |
| אזור אחסון בזיכרון | Heap (וגם String Pool לליטרלים) | Heap | Heap |
public class StringComparisonDemo {
public static void main(String[] args) {
// 1. String: Immutable (Every modification creates a new object in the Heap)
String immutableStr = "Hello";
// A new String object is created in memory; 'immutableStr' now points to it
immutableStr = immutableStr + " World";
System.out.println("String: " + immutableStr);
//output: Hello World
// 2. StringBuilder: Mutable (Modifies the same object in place, highly efficient)
StringBuilder mutableBuilder = new StringBuilder("Hello");
// Appends text to the existing internal buffer without creating new objects
mutableBuilder.append(" World");
mutableBuilder.append(" from Java!");
System.out.println("StringBuilder: " + mutableBuilder.toString());
//output: Hello World from Java!
// 3. StringBuffer: Mutable and Thread-Safe (Synchronized methods for multi-threading)
StringBuffer threadSafeBuffer = new StringBuffer("Safe");
// Safe to use across multiple threads simultaneously due to synchronization overhead
threadSafeBuffer.append(" Threading");
System.out.println("StringBuffer: " + threadSafeBuffer.toString());
//output: Safe Threading
}
}