JavaRush /בלוג Java /Random-HE /מבוא ל-String, StringBuffer ו-StringBuilder ב-Java

מבוא ל-String, StringBuffer ו-StringBuilder ב-Java

פורסם בקבוצה
ישנן שלוש מחלקות ב-Java לעבודה עם נתוני טקסט: String , StringBuffer ו- StringBuilder . כל מפתח פוגש את הראשון כבר בתחילת לימוד השפה. מה עם השניים הנותרים? מה ההבדלים ביניהם, ומתי עדיף להשתמש בכיתה כזו או אחרת? באופן כללי, ההבדל ביניהם קטן, אבל עדיף להבין הכל בפועל :) מבוא ל-String, StringBuffer ו-StringBuilder ב-Java - 1

שיעור מיתר

מחלקה זו מייצגת רצף של תווים. כל מילולי המחרוזת המוגדרים בתוכניות, כגון "This is String" הם מופעים של המחלקה String. למחרוזת שתי תכונות בסיסיות:
  • זה מחלקה בלתי ניתנת לשינוי
  • זה שיעור אחרון
באופן כללי, למחלקה String לא יהיו ילדים ( final) ולא ניתן לשנות מופעים של המחלקה לאחר היצירה ( immutable). זה נותן למחלקה String מספר יתרונות חשובים:
  1. עקב אי-שינוי, ה-hashcode של מופע של המחלקה String נשמר במטמון. אין צורך להעריך אותו בכל פעם כי ערכי השדה של האובייקט לעולם לא ישתנו לאחר יצירתו. זה נותן ביצועים גבוהים כאשר משתמשים במחלקה זו כמפתח עבור HashMap.

  2. ניתן להשתמש במחלקה String בסביבה מרובת הליכים ללא סנכרון נוסף.

  3. תכונה נוספת של המחלקה String היא שהיא מעמיסה על +האופרטור " " ב-Java. לכן, שרשור (הוספה) של מחרוזות הוא די פשוט:

public static void main(String[] args) {
    String command = "Follow" + " " + "the" + " " + "white" + " " + "rabbit";
    System.out.println(command); // Follow the white rabbit
}
מתחת למכסה המנוע, שרשור מחרוזות מתבצע על ידי המחלקה StringBuilder או StringBuffer (לפי שיקול דעתו של המהדר) ושיטה append(על מחלקות אלו נדבר מעט מאוחר יותר). אם נוסיף מופעים של המחלקה String עם מופעים של מחלקות אחרות, האחרון יצטמצם לייצוג מחרוזת:
public static void main(String[] args) {
    Boolean b = Boolean.TRUE;
    String result = "b is " + b;
    System.out.println(result); //b is true
}
זהו עוד תכונה מעניינת של המחלקה String: ניתן להטיל אובייקטים מכל מחלקה לייצוג מחרוזת באמצעות השיטה toString()המוגדרת במחלקה Objectותורשת את כל המחלקות האחרות. לעתים קרובות שיטת toString() באובייקט נקראת באופן מרומז. לדוגמה, כאשר אנו מציגים משהו על המסך או מוסיפים String לאובייקט של מחלקה אחרת. למחלקה String יש תכונה אחת נוספת. כל מילולי המחרוזות המוגדרות בקוד ג'אווה, כגון "asdf", נשמרות במטמון בזמן הקומפילציה ומתווספות למה שנקרא מאגר המחרוזות. אם נריץ את הקוד הבא:
String a = "Wake up, Neo";
String b = "Wake up, Neo";

System.out.println(a == b);
נראה אמת בקונסולה מכיוון שהמשתנים יתייחסו aלמעשה bלאותו מופע של המחלקה String שנוספה למאגר המחרוזות בזמן הקומפילציה. כלומר, לא נוצרים מופעים שונים של המחלקה עם אותו ערך, והזיכרון נשמר.

פגמים:

לא קשה לנחש שהמחלקה String נחוצה בעיקר לעבודה עם מחרוזות. אבל במקרים מסוימים, התכונות שלעיל של מחלקת String יכולות להפוך מיתרונות לחסרונות. לאחר יצירת מחרוזות בקוד Java, פעולות רבות מבוצעות עליהן:
  • המרת מחרוזות לרגיסטרים שונים;
  • מיצוי מחרוזת משנה;
  • שִׁרשׁוּר;
  • וכו '
בואו נסתכל על הקוד הזה:
public static void main(String[] args) {

    String s = " Wake up, Neo! ";
    s = s.toUpperCase();
    s = s.trim();

    System.out.println("\"" + s + "\"");
}
במבט ראשון, נראה שבדיוק תרגמנו את השורה "תתעורר, ניאו!" לאותיות רישיות, הסר רווחים נוספים מהמחרוזת הזו ועטף אותה במירכאות. למעשה, בשל חוסר השינוי של המחלקה String, כתוצאה מכל פעולה, נוצרים מופעי מחרוזת חדשים וישנים נמחקים, מה שיוצר כמות גדולה של זבל. איך להימנע מבזבוז זיכרון?

מחלקה StringBuffer

כדי לטפל ביצירת זבל זמני עקב שינויים באובייקט String, אתה יכול להשתמש במחלקה StringBuffer. זו mutableכיתה, כלומר. מִשְׁתַנֶה. אובייקט של המחלקה StringBuffer יכול להכיל קבוצה מסוימת של תווים, שאת אורכם וערכם ניתן לשנות על ידי קריאה לשיטות מסוימות. בוא נראה איך השיעור הזה עובד. כדי ליצור אובייקט חדש, השתמש באחד מהבנאים שלו, לדוגמה:
  • StringBuffer() - יצור אובייקט ריק (ללא תווים).
  • StringBuffer(String str) - יצור אובייקט המבוסס על המשתנה str (המכיל את כל התווים של str באותו רצף)
תרגול:
StringBuffer sb = new StringBuffer();
StringBuffer sb2 = new StringBuffer("Not empty");
שרשור מחרוזות באמצעות StringBuffer ב-Java נעשה באמצעות append. באופן כללי, השיטה appendבמחלקה StringBuffer עמוסה בצורה כזו שהיא יכולה לקבל כמעט כל סוג נתונים:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2));
    sb.append("; ");
    sb.append(false);
    sb.append("; ");
    sb.append(Arrays.asList(1,2,3));
    sb.append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
השיטה appendמחזירה את האובייקט עליו נקרא (כמו שיטות רבות אחרות), מה שמאפשר לקרוא לו ב"שרשרת". ניתן לכתוב את הדוגמה למעלה כך:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2))
            .append("; ")
            .append(false)
            .append("; ")
            .append(Arrays.asList(1,2,3))
            .append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
למחלקה StringBuffer יש מספר שיטות לעבודה עם מחרוזות. נרשום את העיקריים שבהם:
  • delete(int start, int end)- מוחק מחרוזת משנה של תווים החל ממיקום start, סיוםend
  • deleteCharAt(int index)- מוחק את התו במיקוםindex
  • insert(int offset, String str)- מוסיף קו strבמיקום offset. השיטה insertגם עמוסה ויכולה לקחת טיעונים שונים
  • replace(int start, int end, String str)- יחליף את כל התווים מעמדה startלעמדה endבstr
  • reverse()- הופך את הסדר של כל התווים
  • substring(int start)- יחזיר מחרוזת משנה שמתחילה במיקום start
  • substring(int start, int end)- יחזיר מחרוזת משנה החל ממיקום startלמיקוםend
רשימה מלאה של שיטות ובנאים נמצאת בתיעוד הרשמי . כיצד פועלות השיטות הנ"ל? בוא נראה בפועל:
public static void main(String[] args) {
     String numbers = "0123456789";

     StringBuffer sb = new StringBuffer(numbers);

     System.out.println(sb.substring(3)); // 3456789
     System.out.println(sb.substring(4, 8)); // 4567
     System.out.println(sb.replace(3, 5, "ABCDE")); // 012ABCDE56789

     sb = new StringBuffer(numbers);
     System.out.println(sb.reverse()); // 9876543210
     sb.reverse(); // Return the original order

     sb = new StringBuffer(numbers);
     System.out.println(sb.delete(5, 9)); // 012349
     System.out.println(sb.deleteCharAt(1)); // 02349
     System.out.println(sb.insert(1, "One")); // 0One2349
    }

יתרונות:

  1. כפי שכבר הוזכר, StringBuffer הוא מחלקה ניתנת לשינוי, כך שעבודה איתה לא יוצרת את אותה כמות זבל זיכרון כמו עם String. לכן, אם מבוצעים הרבה שינויים במחרוזות, עדיף להשתמש ב- StringBuffer.

  2. StringBuffer הוא מחלקה בטוחה לחוטים. השיטות שלו מסונכרנות וניתן להשתמש במופעים על ידי שרשורים מרובים בו זמנית.

פגמים:

מצד אחד, בטיחות חוטים היא יתרון של המעמד, ומצד שני, זה חיסרון. שיטות מסונכרנות איטיות יותר משיטות לא מסונכרנות. כאן נכנס לתמונה StringBuilder. בואו להבין איזה סוג של מחלקת Java זה - StringBuilder, אילו שיטות יש לו ומה התכונות שלו.

כיתה StringBuilder

StringBuilder ב-Java הוא מחלקה המייצגת רצף של תווים. זה דומה מאוד ל-StringBuffer בכל המובנים מלבד בטיחות החוטים. StringBuilder מספק API דומה לזה של StringBuffer. בואו נדגים זאת באמצעות דוגמה מוכרת כבר, תוך החלפת ההצהרה של משתנים מ-StringBufer ל-StringBuilder:
public static void main(String[] args) {
    String numbers = "0123456789";

    StringBuilder sb = new StringBuilder(numbers);

    System.out.println(sb.substring(3)); //3456789
    System.out.println(sb.substring(4, 8)); //4567
    System.out.println(sb.replace(3, 5, "ABCDE")); //012ABCDE56789

    sb = new StringBuilder(numbers);
    System.out.println(sb.reverse()); //9876543210
    sb.reverse(); // Return the original order

    sb = new StringBuilder(numbers);
    System.out.println(sb.delete(5, 9)); //012349
    System.out.println(sb.deleteCharAt(1)); //02349
    System.out.println(sb.insert(1, "One")); //0One2349
}
ההבדל היחיד הוא ש-StringBuffer בטוח בשרשור וכל השיטות שלו מסונכרנות, בעוד ש-StringBuilder לא. זוהי התכונה היחידה. StringBuilder ב-Java מהיר יותר מ-StringBuffer בגלל אי-סנכרון של שיטות. לכן, ברוב המקרים, למעט בסביבה מרובה הליכי, עדיף להשתמש ב-StringBuilder עבור תוכנית Java. אנו מסכמים הכל בטבלה השוואתית של שלושת הכיתות:

String לעומת StringBuffer לעומת StringBuilder

חוּט StringBuffer StringBuilder
יכולת שינוי Immutable(לא) mutable(כן) mutable(כן)
פְּרִישׁוּת final(לא) final(לא) final(לא)
בטיחות חוטים כן, בגלל חוסר שינוי כן, עקב סנכרון לא
מתי להשתמש כאשר עובדים עם מחרוזות שלעתים נדירות ישתנו כאשר עובדים עם מחרוזות שישונו לעתים קרובות בסביבה מרובת חוטים כאשר עובדים עם מחרוזות שישתנו לעתים קרובות בסביבה עם חוטים בודדים
אתה יכול ללמוד את הנושא הזה בפירוט רב יותר ברמה השנייה של קווסט Java Multithreading בקורס JavaRush:
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION