איטרטור חסר כישלון לעומת איטרטור מהיר

1. הקדמה

במאמר זה נציג את המושג Fail-Fast ו- Fail-Safe מחטבים.

מערכות כושלות מהירות מבטלות את הפעולה במהירות האפשרית וחושפות כשלים באופן מיידי ועוצרות את כל הפעולה.

ואילו, מערכות כשל-בטוח אינן מבטלות פעולה במקרה של תקלה. מערכות כאלה מנסות להימנע ככל האפשר מהעלאת כשלים.

2. כישלון מהיר מחטבים

איטרטורים מהירים בכישלון ב- Java אינם משחקים כאשר האוסף הבסיסי משתנה.

אוספים לשמור על דלפק פנימי שנקרא modCount. בכל פעם פריט מתווסף או מוסר מה- אוסף, הדלפק הזה מתגבר.

כשמתחדש, על כל אחד הַבָּא() שיחה, הערך הנוכחי של modCount מקבל בהשוואה לערך ההתחלתי. אם יש חוסר התאמה, זה זורק ConcurrentModificationException המפיל את כל הפעולה.

איטרטורים ברירת מחדל עבור אוספים מ חבילת java.util כמו רשימת מערך, מפת גיבובוכו 'אינם מהירים.

מספרי ArrayList = // ... איטרטור איטרטור = numbers.iterator (); ואילו (iterator.hasNext ()) {מספר שלם = iterator.next (); numbers.add (50); }

בקטע הקוד שלמעלה, ConcurrentModificationException נזרק בתחילת מחזור איטרציה הבא לאחר ביצוע השינוי.

לא מובטח שההתנהגות של כישלון מהיר תתרחש בכל התרחישים מכיוון שאי אפשר לחזות התנהגות במקרה של שינויים מקבילים. האיטרטים האלה זורקים ConcurrentModificationException על בסיס המאמץ הטוב ביותר.

אם במהלך איטרציה על פני א אוסף, פריט מוסר באמצעות איטרטורשל לְהַסִיר() שיטה, זה בטוח לחלוטין ואינו זורק חריג.

עם זאת, אם אוסףשל לְהַסִיר() השיטה משמשת להסרת אלמנט, והיא מציגה חריג:

מספרי ArrayList = // ... איטרטור איטרטור = numbers.iterator (); בעוד (iterator.hasNext ()) {if (iterator.next () == 30) {iterator.remove (); // בסדר! }} איטרטור = numbers.iterator (); בעוד (iterator.hasNext ()) {if (iterator.next () == 40) {numbers.remove (2); // יוצא מן הכלל } }

3. איטרטורים חסרי כשל

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

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

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

זה אומר, אםאוסף משתנה תוך כדי איטרציה, מה איטרטור רואה מובטח חלש. התנהגות זו עשויה להיות שונה מבחינת שונות אוספים ומתועד ב- Javadocs של כל אחד כזה אוסף.

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

חסרון נוסף הוא התקורה ליצירת עותק של ה- אוסף, הן לגבי זמן והן זיכרון.

מחטבים עַל אוספים מ java.util.concurrent חבילה כגון ConcurrentHashMap, CopyOnWriteArrayListוכו 'הם אופייניים כשלים.

ConcurrentHashMap map = ConcurrentHashMap חדש (); map.put ("ראשית", 10); map.put ("שני", 20); map.put ("שלישי", 30); map.put ("הרביעי", 40); איטרטור איטרטור = map.keySet (). איטרטור (); בעוד (iterator.hasNext ()) {מפתח מחרוזת = iterator.next (); map.put ("החמישי", 50); }

בקטע הקוד שלמעלה אנו משתמשים ב- Fail-Safe איטרטור. לפיכך, למרות שמתווסף אלמנט חדש אוסף במהלך איטרציה זה לא יוצא חריג.

איטרטור ברירת המחדלבשביל ה ConcurrentHashMap הוא עקבי חלש. זה אומר שזה איטרטור יכול לסבול שינוי במקביל, חוצה אלמנטים כפי שהיו קיימים בעת איטרטור נבנה ועשוי (אך לא מובטח שהוא) לשקף שינויים ב- אוסף לאחר בניית בית ההארחה איטרטור.

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

4. מסקנה

במדריך זה ראינו מה Fail-Safe ו- Fail-Fast מחטבים מתכוון וכיצד אלה מיושמים בג'אווה.

הקוד השלם המוצג במאמר זה זמין באתר GitHub.