{
  "assessmentTests": {
    "java_test": {
      "name": "מבחן Java",
      "desc": "30 שאלות תרחיש על תחביר ליבה, מכניקת OOP, קולקציות, ג'ניריקס, חריגים ותאום — גלה אם Java שלך תואם את מה שהודעת משרה מתכוונת ב-Java.",
      "recommendation": "פרופיל הכישורים שלך ב-Java",
      "results": {
        "beginner": {
          "name": "למתחילים",
          "desc": "אתה יכול לכתוב מחלקות ושיטות עובדות, אבל השאלות שפספסת מתקבצות סביב זהות וברירות מחדל ולא תחביר — String == מול .equals, למה new String(\"x\") לא מעולם משתמש בצי המחרוזות, מה שדה מספרי ברירת מחדל לעומת שדה wrapper. זה לא קשור להיות רע ב-Java; אלה הכללים הספציפיים שתופסים אנשים שלמדו את השפה בניסוי וטעייה ולא מאופן שהפניות ופרימיטיביים בעצם עובדים מתחת למכסה המנוע. הם משנים בעבודה כי כל אחד מהם הוא מקום שבו קוד מתורגם, רץ, ועושה בשקט את הדבר הלא נכון.",
          "recommendation": "התחל בשלוש דברים, לפי הסדר הזה: למה == על שני אובייקטי String משווה הפניות, לא תווים (ו-.equals הוא מה שאתה כמעט תמיד רוצה), איך int overflow עוטף בשקט במקום לזרוק, ולמה שדה Integer לא מותחל מגדיר בשקט null בעוד שדה int מגדיר 0. הטוטוריאלים הרשמיים של Oracle וBaeldung שניהם מכסים את שלושת הדברים עם דוגמאות ניתנות להפעלה."
        },
        "intermediate": {
          "name": "ביניים",
          "desc": "אתה מטפל בקוד יישום יומיומי בנוחות — מחלקות, קולקציות, זרימת בקרה ישרה — ולא היית מואט בעבודת תכונות שגרתית. הפער בין כאן וAdvanced הוא בעיקר מה קורה כשהכללים של Java יוצרים אינטראקציה עם concurrency וג'ניריקס: שיטה סטטית שנפתרה לפי סוג מוצהר במקום את האובייקט שציפית, סדר איטרציה של HashMap שהסתמכת בשקט עליו, ConcurrentModificationException מהסרת פריט באמצע הלולאה. אלה הסוגים של באגים שעוברים קריאה מהירה ורק מופיעים תחת תנאי זמן ריצה ספציפי.",
          "recommendation": "התמקד איך הנקודת המבט הסטטית של המהדר שלך שונה מאלה שרץ: overload resolution ושיטה-סטטית-hiding לפי סוג מוצהר ולא סוג זמן ריצה, למה HashMap לא נותן ערבות סדר איטרציה, ולמה שינוי רשימה ישיר בזמן איטרציה זורק ConcurrentModificationException. אחר כך generics erasure, מכיוון שזה תופס אנשים שכבר מכירים קולקציות בנפרד."
        },
        "advanced": {
          "name": "מתקדם",
          "desc": "זו הרמה שרוב הודעות משרה מתכוונות ב\"Java חזק.\" אתה קורא מחלקה עם static blocks, instance blocks ומספר בנאים ויכול לחזות את סדר הריצה בדיוק, אתה יודע למה a finally block יכול בשקט להטיל את ערך ההחזרה של כל בלוק try בצד, והחלפה try-with-resources במקום manual finally-close כי אתה מכיר את ערבות ההזמנה שהוא נותן לך. מה שמפריד את הבנד הזה מהחלק העליון היא הצד של concurrency והרמה interfaceית של העבודה: מה synchronized בעצם נועל, מה volatile עושה וגם לא מבטיח, וכיצד default-method conflicts מקבלים פתרון.",
          "recommendation": "דחוף לחלקים שמגנים על קוד שthreads אחרים וinterfaces אחרים גם נוגעים בהם: ההבדל בין מה של synchronized instance method נועל מול synchronized static method, למה volatile נותן visibility אבל לא atomicity עבור counter++, וכיצד Java כופה עליך לפתור את diamond conflict של default-method בעצמך. החומר של Baeldung וJava Concurrency in Practice על Java Memory Model הוא המקום הטבעי הבא לשניהם."
        },
        "expert": {
          "name": "מומחה",
          "desc": "ניקדת בחלק העליון של כל סוג — תחביר ליבה וסוגים, מכניקת OOP וטווח, קולקציות וג'ניריקס, וחריגים, concurrency ואידיומים. בפרקטיקה, זה אומר אתה יכול להיות מועבר מחלקה של זר והסביר למה compile error, runtime exception, או ערך בשקט לא נכון קורה, לא רק מה התחביר אומר שזה צריך לעשות, שהיא המיומנות קשה יותר וערכונית יותר. ברמה הזו השפה עצמה כמעט לעולם אינה הגורם המגביל; הגבול הוא בדרך כלל concurrency design או הצורה של הנתונים שמתחתיו.",
          "recommendation": "ההחזרות הן כעת בעיצוב וביחוס: קריאת thread dump לפני הנחה שהתליה היא deadlock, בחירה בין synchronized, java.util.concurrent locks ו-atomics כחליפה ולא כברירת מחדל, וstream-pipeline design שנשאר lazy בכוונה ולא בתאונה. אם אתה מעורב בבדיקה לתפקיד, תאר bug concurrency כמו missed happens-before edge או ConcurrentModificationException שמצאת בייצור ולא שמות תכונות Java — זה מדגים את ההיגיון, לא רק את אוצר המילים."
        }
      },
      "questions": [
        {
          "question": "אתה יוצר שני אובייקטי String: String a = new String(\"cat\"); String b = new String(\"cat\"); מה a == b מעריך?",
          "options": [
            {
              "icon": "",
              "label": "true — String literals עם אותם תווים תמיד אותו אובייקט"
            },
            {
              "icon": "",
              "label": "true — new String(...) משתמש מחדש בstring pool, אז טקסט זהה תמיד חולק אובייקט אחד"
            },
            {
              "icon": "",
              "label": "compile error — == לא יכול לשמש להשוואת אובייקטי String"
            },
            {
              "icon": "",
              "label": "false — new String(...) תמיד מקצה אובייקט חדש בheap, כך == משווה שתי הפניות שונות למרות ש-.equals(b) היה חוזר true"
            }
          ]
        },
        {
          "question": "Integer x = 100; Integer y = 100; System.out.println(x == y); ואז Integer x2 = 200; Integer y2 = 200; System.out.println(x2 == y2); מה שני הקווים מדפיסים?",
          "options": [
            {
              "icon": "",
              "label": "true אחר כך true — אובייקטי Integer שעברו autoboxing תמיד בקשה ערך ללא הגבלה"
            },
            {
              "icon": "",
              "label": "false אחר כך false — == על אובייקטי Integer הוא תמיד השוואת הפניה, אז ערכים שווים לעולם לא תואמים"
            },
            {
              "icon": "",
              "label": "true אחר כך false, אבל רק כי 200 overflow byte — גבול המטמון קשור הערה ל--128..127"
            },
            {
              "icon": "",
              "label": "true אחר כך false — ערכי Integer שעברו autoboxing מ--128 עד 127 מטומנים ומשותפים, כך 100 משתמש מחדש אובייקט אחד, אבל 200 נופל מחוץ למטמון ויוצא autoboxes לשני אובייקטים נפרדים"
            }
          ]
        },
        {
          "question": "int max = Integer.MAX_VALUE; System.out.println(max + 1); מה קורה?",
          "options": [
            {
              "icon": "",
              "label": "זה זורק ArithmeticException עבור integer overflow"
            },
            {
              "icon": "",
              "label": "זה מדפיס Integer.MAX_VALUE שוב, כי Java מקמץ בגובה הסוג של הסוג"
            },
            {
              "icon": "",
              "label": "זה מדפיס Integer.MIN_VALUE — int arithmetic בשקט עוטף סביב על overflow במקום לזרוק"
            },
            {
              "icon": "",
              "label": "זה compile error — המהדר מזהה את overflow מראש"
            }
          ]
        },
        {
          "question": "System.out.println(0.1 + 0.2 == 0.3); מה זה מדפיס, ולמה?",
          "options": [
            {
              "icon": "",
              "label": "false — 0.1, 0.2 ו-0.3 לא יכול להיות מייצג בדיוק בבינארי floating point, אז הסכום נושא שגיאת עיגול שעושה זה לא bit-for-bit שווה ל-0.3"
            },
            {
              "icon": "",
              "label": "true — Java מעגל double arithmetic לקרוב ייצוגי עשרוני לפני השוואה"
            },
            {
              "icon": "",
              "label": "true — הוספת שני doubles תמיד בדיוק עבור ערכים עם שני מקומות עשרוניים"
            },
            {
              "icon": "",
              "label": "זה זורק exception, כי == לא מוגדר עבור double ב-Java"
            }
          ]
        },
        {
          "question": "מחלקה מצהירה שני שדות instance ללא initializer: int count; ו-Integer total; לפני שהבנאי רץ, מה ערכי ברירת המחדל שלהם?",
          "options": [
            {
              "icon": "",
              "label": "שניהם default ל-0, כי Integer autoboxes ל-int בinitialization של שדה"
            },
            {
              "icon": "",
              "label": "count הוא 0 ו-total הוא 0, boxed באופן אוטומטי הפעם הראשונה שהוא קרא"
            },
            {
              "icon": "",
              "label": "count הוא 0 ו-total הוא null — שדות numeric פרימיטיביים default לאפס, אבל שדה reference wrapper לא מותחל defaults ל-null כמו כל הפניה אובייקט אחרת"
            },
            {
              "icon": "",
              "label": "שניהם default ל-null עד שנקבעים בעצמי, מכיוון Java אין ברירות מחדל מספריות מובנות"
            }
          ]
        },
        {
          "question": "לולאה רץ 1000 פעמים, כל פעם עשיית result += \"x\"; על String result. מה בעצם קורה תחת ההוד כל איטרציה?",
          "options": [
            {
              "icon": "",
              "label": "מערך התווים הפנימי של אובייקט String הקיים מורחב במקום"
            },
            {
              "icon": "",
              "label": "Java באופן אוטומטי אגד את concatenations ורק מקצה אובייקט String סופי אחד"
            },
            {
              "icon": "",
              "label": "זה קומפיל ל-StringBuilder.append() קריאה אחת משותפת על פני כל 1000 איטרציות, עם אובייקט אחרא נוצר לא לכל איטרציה"
            },
            {
              "icon": "",
              "label": "אובייקט String חדש לגמרי נוצר וresult מתוקצה כדי להצביע עליו — אובייקט String קודם הוא מושלך, כי String הוא immutable ו-+= לא יכול לשנות זה במקום"
            }
          ]
        },
        {
          "question": "final List<String> names = new ArrayList<>(); איזו מאלה נכונה?",
          "options": [
            {
              "icon": "",
              "label": "names.add(\"Ana\") קומפיל וועובד בסדר — final רק מונע תוקצה מחדש של הפניית names עצמו, לא mutation של אובייקט זה מצביע עליו"
            },
            {
              "icon": "",
              "label": "names.add(\"Ana\") הוא compile error, כי final עושה הרשימה עצמה unmodifiable"
            },
            {
              "icon": "",
              "label": "הרשימה היא thread-safe עבור concurrent writes כי זה הוצהר final"
            },
            {
              "icon": "",
              "label": "final על משתנה מקומי יש שום השפעה אלא אם הסוג גם מוצהר immutable"
            }
          ]
        },
        {
          "question": "int[] a = {1, 2, 3}; int[] b = {1, 2, 3}; System.out.println(a == b); System.out.println(Arrays.equals(a, b)); מה שני הקווים מדפיסים?",
          "options": [
            {
              "icon": "",
              "label": "false אחר כך true — == משווה מערך הפניות (שני אובייקטי מערך שונים), בזמן Arrays.equals משווה את האלמנטים"
            },
            {
              "icon": "",
              "label": "true אחר כך true — מערכים עם תוכן זהה הם אובייקט אחד ב-Java"
            },
            {
              "icon": "",
              "label": "false אחר כך false — Arrays.equals רק עובד עבור אובייקט מערכים, לא primitive int מערכים"
            },
            {
              "icon": "",
              "label": "true אחר כך false — == על מערכים משווה תוכן, ו-Arrays.equals הוא מיותר"
            }
          ]
        },
        {
          "question": "void show(Object o) { print(\"Object\"); } void show(String s) { print(\"String\"); } Object ref = \"hello\"; show(ref); איזה overload רץ, ולמה?",
          "options": [
            {
              "icon": "",
              "label": "show(String) רץ, כי Java משפים את המחלקה בעל הזמן ריצה של אובייקט לפני בחירת overload"
            },
            {
              "icon": "",
              "label": "show(Object) רץ — overload resolution מוכרע בזמן קומפיל שימוש בסוג המוצהר של המשתנה, לא סוג זמן ריצה בעל אובייקט שהוא מתייחס"
            },
            {
              "icon": "",
              "label": "זה compile error — Object לא יכול להיות מועבר שם overload יותר ספציפי קיים"
            },
            {
              "icon": "",
              "label": "שתי השיטות רץ, פעם אחת כל אחד, כי Java פותרת overloads על ידי ניסיון כל התאמה"
            }
          ]
        },
        {
          "question": "מחלקה Base יש static void greet() { print(\"Base\"); }. מחלקה Derived מרחיבה Base וגם מצהירה static void greet() { print(\"Derived\"); }. אתה כותב: Base ref = new Derived(); ref.greet(); מה מדפיס?",
          "options": [
            {
              "icon": "",
              "label": "Derived — static שיטות override בדיוק כמו instance שיטות, ועוקב אחרי סוג זמן ריצה בעל אובייקט"
            },
            {
              "icon": "",
              "label": "זה compile error — static שיטות לא יכול להיות קרא דרך instance הפניה"
            },
            {
              "icon": "",
              "label": "Base — static שיטות לא polymorphic; קריאה אחד דרך הפניה פותר לפי סוג מוצהר של הפניה בזמן קומפיל, לא סוג בעל אובייקט בעל זמן ריצה"
            },
            {
              "icon": "",
              "label": "שניהם Base ו-Derived מדפיסים, כי הקריאה פתרות לשניהם הסתתר וגם hiding גרסאות"
            }
          ]
        },
        {
          "question": "בתוך שיטה, אתה כותב int count = 0; ואחר כך מנסה להפנות count מבתוך lambda מעביר לשיטה אחרת. מה חייב להיות נכון על count כך שזה קומפיל?",
          "options": [
            {
              "icon": "",
              "label": "count חייב להיות effectively final — לעולם לא מתוקצה מחדש אחרי ערך ההתחלתי שלה — כי lambda לוקח snapshot, לא הפניה חיה למשתנה מקומי ניתן לשינוי"
            },
            {
              "icon": "",
              "label": "כלום — כל משתנה מקומי יכול להיות בחופשיות קרא והתוקצה מחדש מתוך lambda"
            },
            {
              "icon": "",
              "label": "count חייב להיות מוצהר volatile אז lambda תמיד רואה את ערכו העדכני"
            },
            {
              "icon": "",
              "label": "count חייב להיות שדה, לא משתנה מקומי — lambdas לא יכול ללכוד מקומות כל כך"
            }
          ]
        },
        {
          "question": "void rename(StringBuilder sb) { sb = new StringBuilder(\"new\"); } הוא קרא כ-StringBuilder original = new StringBuilder(\"old\"); rename(original); מה הוא original אחרי הקריאה?",
          "options": [
            {
              "icon": "",
              "label": "הופך ל-\"new\" — אובייקטים הם מעביר בהפניה ב-Java, אז תוקצה המחדש של הפרמטר משנה משתנה של הקורא גם כן"
            },
            {
              "icon": "",
              "label": "הופך ל-\"new\" רק עבור סוגים ניתנים לשינוי כמו StringBuilder, אבל לא עבור סוגים immutable"
            },
            {
              "icon": "",
              "label": "עדיין \"old\" — Java מעביר הפניה עצמה לפי ערך, אז תוקצה המחדש של הפרמטר בתוך השיטה רק repoints את עותק מקומי של הפניה, משאיר את המקורי של הקורא ללא נגיעה"
            },
            {
              "icon": "",
              "label": "זורק runtime exception, כי sb הוא מתוקצה מחדש בתוך השיטה"
            }
          ]
        },
        {
          "question": "מחלקה יש static initializer block, instance initializer block, ובנאי, בסדר source זה. אתה יוצר שני אובייקטים של מחלקה זו אחד אחרי השני. בסדר מה הם יש להריץ?",
          "options": [
            {
              "icon": "",
              "label": "ה-static block רץ בדיוק פעם אחת, הפעם הראשונה השדה הוא טעון; אז עבור כל אובייקט, ה-instance block רץ ואחר כך הבנאי גוף רץ"
            },
            {
              "icon": "",
              "label": "כל שלוש רץ טרי, לפי סדר source, עבור כל אובייקט בודד נוצר"
            },
            {
              "icon": "",
              "label": "הבנאי רץ ראשון עבור כל אובייקט, אחר כך ה-instance block, אחר כך ה-static block פעם אחת בסוף מאוד"
            },
            {
              "icon": "",
              "label": "ה-static block רץ פעם לכל אובייקט, ממש לפני ה-instance block"
            }
          ]
        },
        {
          "question": "מחלקה יש void log(String s) ו-void log(String... args). אתה קוראים log(\"hi\"). איזה אחד רץ?",
          "options": [
            {
              "icon": "",
              "label": "log(String... args) — varargs overloads כמעט תמיד עדיפות כששניהם ישימים"
            },
            {
              "icon": "",
              "label": "זה compile error — הקריאה היא דו-משמעית בין שני overloads"
            },
            {
              "icon": "",
              "label": "log(String s) — כשfixed-arity overload תואם בדיוק, Java תמיד מעדיפה זה על varargs overload, אשר רק משמש כ-last resort"
            },
            {
              "icon": "",
              "label": "הואחד מוצהר ראשון בקובץ source רץ"
            }
          ]
        },
        {
          "question": "בנאי הקו הראשון שלה קוראים this(0); כדי להתאים לבנאי אחר באותה מחלקה. איפה זה מותר להופיע?",
          "options": [
            {
              "icon": "",
              "label": "כל מקום בגוף בנאי, כל עוד זה רץ לפני האובייקט הוא חוזר"
            },
            {
              "icon": "",
              "label": "רק כ-statement הראשונה בדיוק של הבנאי — this() (או super()) חייב להיות קו הראשון, ובנאי לא יכול לקרוא לשניהם זה() ו-super()"
            },
            {
              "icon": "",
              "label": "רק כ-statement אחרון, אחרי כל field initialization הוא כמוי"
            },
            {
              "icon": "",
              "label": "רק בבנאים שסימנו במפורש כmisallocation, באמצעות delegate מילת מפתח"
            }
          ]
        },
        {
          "question": "אתה צריך רשימה שתהיה אלמנטים הכנס בחזית מאד לעתים קרובות, ו-random-access קורא הם hierar. איזה הוא תאום של structural טוב יותר, ולמה?",
          "options": [
            {
              "icon": "",
              "label": "ArrayList — שלה contiguous backing מערך עושה כל פעולה, כולל front-insertion, מהר יותר מ-linked מבנה"
            },
            {
              "icon": "",
              "label": "הם bietet זהה, כי שניהם יישום ה-List ממשק עם אותה זמן מבטחות"
            },
            {
              "icon": "",
              "label": "LinkedList — הכנס בחזית הוא O(1) כי זה רק relinks צומת, בעוד ArrayList צריך כדי משמרת כל אלמנט קיים עד על ידי אחד, ביצוע front-insertion O(n)"
            },
            {
              "icon": "",
              "label": "LinkedList, כי זה תומך random access בO(1) בעוד ArrayList לא"
            }
          ]
        },
        {
          "question": "אתה הכנס חמש ערכים לתוך רגיל HashMap בסדר ספציפי, אחר כך איטרציה על זה עם for-each לולאה. איזה סדר האלמנטים בא החוצה?",
          "options": [
            {
              "icon": "",
              "label": "אותו סדר הערכים הכנסו בה, מאז Java מפות תמיד להישמר הכנסה סדר"
            },
            {
              "icon": "",
              "label": "לא בטוח סדר כלל — HashMap של איטרציה סדר תלוי בhash bucket מצב, לא הכנסה סדר, וביכול אפילו להשתנות בין רץ; LinkedHashMap הוא מה משמר הכנסה סדר"
            },
            {
              "icon": "",
              "label": "מסודר לפי מפתח באופן אוטומטי, באותה דרך TreeMap התנהגות"
            },
            {
              "icon": "",
              "label": "להפוך של הכנסה סדר, כי HashMap פנימית שימוש ערמה"
            }
          ]
        },
        {
          "question": "כמה null מפתחות יכול לא java.util.HashMap להחזיק בבת אחד, וכמה null ערכים?",
          "options": [
            {
              "icon": "",
              "label": "לא null מפתחות ולא null ערכים לעולם מוצהר בכל Map יישום"
            },
            {
              "icon": "",
              "label": "אחד null מפתח ברוב, וכל מספר של null ערכים — HashMap מאפשר בודד null מפתח, בניגוד Hashtable אשר מאפשר לא"
            },
            {
              "icon": "",
              "label": "בלא מוגבל null מפתחות ובלא מוגבל null ערכים, מאז null הוא התייחס כמו כל מפתח אחר"
            },
            {
              "icon": "",
              "label": "אחד null מפתח ו-אחד null ערך מקסימום, שניהם capped בוחד"
            }
          ]
        },
        {
          "question": "אתה איטרציה List עם for-each לולאה וקורא list.remove(item) ישירות על הרשימה מתוך גוף הלולאה, בחלק אבל לא כל אלמנטים. מה קורה?",
          "options": [
            {
              "icon": "",
              "label": "זה עובד בהצלחה וגם מסיר כמו מכוון אלמנטים"
            },
            {
              "icon": "",
              "label": "זה בשקט דלג האלמנט אחרי אחד מוסר, אבל אחרת שלם ללא שגיאה"
            },
            {
              "icon": "",
              "label": "זה זורק IndexOutOfBoundsException פעם הלולאה מגיע הישן גודל של הרשימה"
            },
            {
              "icon": "",
              "label": "זה זורק ConcurrentModificationException — שינוי של הרשימה את המבנה ישירות בזמן implicit איטרציה הוא הלך ו-rejected; Iterator.remove() חייב להיות משמש במקום"
            }
          ]
        },
        {
          "question": "בזמן ריצה, נתון List<String> list, מה אתה בעצם יכול להקבע על הג'נריק סוג פרמטר דרך החזר או instanceof?",
          "options": [
            {
              "icon": "",
              "label": "אתה יכול לקרוא list.getElementType() כדי לקבל String.class בזמן ריצה"
            },
            {
              "icon": "",
              "label": "instanceof List<String> קומפיל ובנכון בודק סוג אלמנט"
            },
            {
              "icon": "",
              "label": "ה-JVM אחסן הסוג פרמטר כ-hidden metadata accessible דרך list.getGenericType()"
            },
            {
              "icon": "",
              "label": "כלום — תמונה מלא סוג מידע הוא מחוק בזמן קומפיל, אז בזמן ריצה האובייקט הוא בדיוק רשימה, ותהיה אין דרך כדי שחזור בו זה הוא מוצהר List<String> או List<Integer>"
            }
          ]
        },
        {
          "question": "switch (day) { case 1: case 2: print(\"Weekday\"); break; case 6: print(\"Saturday\"); case 7: print(\"Sunday\"); break; default: print(\"?\"); } אם day הוא 6, מה מדפיס?",
          "options": [
            {
              "icon": "",
              "label": "רק Saturday — כל case בלוק בswitch תמיד עצור אחרי שלה print statement"
            },
            {
              "icon": "",
              "label": "רק Sunday — matching מתחיל בcase 6 אבל רק אחרון match תווית לפני break ביצוע"
            },
            {
              "icon": "",
              "label": "כלום מדפיס, כי day 6 אין match case עם הוא break קובע ישר מתחתיו"
            },
            {
              "icon": "",
              "label": "Saturday אחר כך Sunday — case 6 אין break, אז ביצוע נופל דרך לתוך הבא case של קוד לפני פגע הבא break"
            }
          ]
        },
        {
          "question": "מוצר מחלקה צרכים בודד, ברור \"טבעי\" סדר מיון לפי מחיר, בתוספת יכולת כדי גם מיון לפי שם או על ידי מניות רמה במקומות שונים בקוד. איזה צירוף הוא זכות דיזיין?",
          "options": [
            {
              "icon": "",
              "label": "יישום Comparable<Product> שלוש פעמים נפרדות, אחד סדר, ותן הקורא לבחור איזה compareTo רץ"
            },
            {
              "icon": "",
              "label": "יישום Comparable<Product> עבור טבעי מחיר סדר, וכתוב נפרד Comparator<Product> מופעים עבור שם וmock רמה orderings משמש אחרת"
            },
            {
              "icon": "",
              "label": "שימוש רק Comparator עבור כל סדר, כולל מחיר, מאז Comparable יש שום יתרון כאן"
            },
            {
              "icon": "",
              "label": "שימוש רק Comparable על ידי הוספה שלוש העמיסו compareTo שיטות, אחד סדר"
            }
          ]
        },
        {
          "question": "שיטה קוראים new FileReader(path), אשר מצהירה throws IOException. IOException מרחיב Exception, לא RuntimeException. מה חייב אתה עשה כדי לעשות זה קומפיל?",
          "options": [
            {
              "icon": "",
              "label": "כלום — המהדר רק כופה זה עבור יוצאים שתרחב RuntimeException"
            },
            {
              "icon": "",
              "label": "גם תפוס IOException בתוך try/catch או מצהירים throws IOException על שלך שלך שיטה — בדוק יוצאים חייב להיות טיפל או propagated במפורש, בניגוד unchecked RuntimeException תת-מחלקות"
            },
            {
              "icon": "",
              "label": "עטוף הקריאה בתוך try/catch עבור RuntimeException, מאז IOException הוא באופן אוטומטי unchecked בחזון Java"
            },
            {
              "icon": "",
              "label": "מצהירים השיטה כstaticisInstanceOf — static שיטות הם פטור מטיפול חריגה בדוק"
            }
          ]
        },
        {
          "question": "try (Resource a = new Resource(\"A\"); Resource b = new Resource(\"B\")) { ... } משתמש שני משאבים יישום AutoCloseable. אם ה-try בלוק תמיים בעדינות, בסדר מה הם סגור?",
          "options": [
            {
              "icon": "",
              "label": "A הוא סגור ראשון, אחר כך B, השחקה הכרזה סדר"
            },
            {
              "icon": "",
              "label": "B הוא סגור ראשון, אחר כך A — try-with-resources משאבים סגור בהפוך של סדר הם הוכרז"
            },
            {
              "icon": "",
              "label": "שניהם סגור בו זמנית, מאז try-with-resources מקביל ניקיון"
            },
            {
              "icon": "",
              "label": "רק B הוא סגור באופן אוטומטי — A עדיין חייב להיות סגור באופן ידני בfinally בלוק"
            }
          ]
        },
        {
          "question": "int getValue() { try { return 1; } finally { return 2; } } מה קורא getValue() חוזר?",
          "options": [
            {
              "icon": "",
              "label": "1 — ה-try בלוק של ערך החזר כבר התחייב לפני finally רץ, אז finally לא יכול להחליף זה"
            },
            {
              "icon": "",
              "label": "זה זורק exception בזמן ריצה, כי שיטה לא יכול לחזור משני מקומות"
            },
            {
              "icon": "",
              "label": "2 — return statement בתוך finally רקע ותחליף כל החזר כבר בתוך ה-try בלוק, מחיקה הערך 1 לגמרי"
            },
            {
              "icon": "",
              "label": "זה compile error — finally לא מותר מכיל return statement"
            }
          ]
        },
        {
          "question": "try { ... } catch (IOException e) { ... } catch (FileNotFoundException e) { ... }, ו-FileNotFoundException מרחיב IOException. מה קורה כשאתה מנסה קומפיל זה?",
          "options": [
            {
              "icon": "",
              "label": "compile error — ה-FileNotFoundException לתפוס בלוק הוא בלתי הגיע כי הקודם, יותר כללי IOException לתפוס בלוק כבר תואמים כל FileNotFoundException"
            },
            {
              "icon": "",
              "label": "זה קומפיל בסדר, וה-יותר ספציפי FileNotFoundException בלוק רץ כל פעם שסוג בדיוק זה הוא זרוק"
            },
            {
              "icon": "",
              "label": "זה קומפיל בסדר, ושניהם לתפוס בלוקים רץ לפי סדר עבור FileNotFoundException"
            },
            {
              "icon": "",
              "label": "זה בסדר בקומפיל זמן אבל זורק runtime שגיאה הפעם הראשונה FileNotFoundException בעצם קורה"
            }
          ]
        },
        {
          "question": "מחלקה יש synchronized instance שיטה process() ו-synchronized סטטי שיטה configure(). מה, בתוך, עושה כל אחד לנעול?",
          "options": [
            {
              "icon": "",
              "label": "process() נועל את הצג של הספציפי אובייקט מופע זה של קרא עליו, בזמן configure() נועל את הצג של ה-Class אובייקט עצמו — משותף על ידי כל מופע"
            },
            {
              "icon": "",
              "label": "שניהם נעל אותו בודד גלובל לנעול עבור כל ה-JVM, ללא קשר לבחדו או מחלקה"
            },
            {
              "icon": "",
              "label": "process() נעל ה-Class אובייקט, ו-configure() נעל איזה אובייקט קורא זה"
            },
            {
              "icon": "",
              "label": "לא אחד בעצם נוועל כלום אלא אם synchronized בלוק גם משמש בתוך שיטה גוף"
            }
          ]
        },
        {
          "question": "שדה הוא מוצהר volatile int counter = 0;, ו-multiple threads רץ counter++ עליו concurrently. האם volatile מונע אבד עדכונים כאן?",
          "options": [
            {
              "icon": "",
              "label": "כן — volatile עושה כל פעולה על השדה atomic, כולל increments"
            },
            {
              "icon": "",
              "label": "לא — volatile רק גורנטיסט שקורא ראה הכתוב הטרון בחוט, כל משהו טוב ב-volatile לא לעשות הם atomic"
            },
            {
              "icon": "",
              "label": "כן, אבל רק עבור int ו-long שדות במיוחד, בגלל איך ה-JVM ידל 64-bit ערכים"
            },
            {
              "icon": "",
              "label": "לא, וvolatile גם לא גורנטיסט visibility עבור סוגים פרימיטיביים כמו int"
            }
          ]
        },
        {
          "question": "Interface A וinterface B כל מצהירים כברירת מחדל שיטה describe(). מחלקה יישם שניהם A ו-B ולא override describe() עצמו. מה קורה?",
          "options": [
            {
              "icon": "",
              "label": "המהדר בוחר interface A של גרסה באופן אוטומטי, מאז זה נרשם ראשון בimplements סעיף"
            },
            {
              "icon": "",
              "label": "שתי גרסאות רץ, אחד אחרי אחד, כלשהו describe() הוא קרא"
            },
            {
              "icon": "",
              "label": "זה בסדר בקומפיל זמן, אבל זורק AmbiguousMethodException הפעם הראשונה describe() הוא קרא"
            },
            {
              "icon": "",
              "label": "compile error — כלשהו שתי ממשק תרומה אותו כברירת מחדל שיטה, יישם מחלקה חייב override זה עצמו כדי לפתור את דו-משמעות, מאז Java לא בואה לנחש איזה אחד אתה התכוון"
            }
          ]
        },
        {
          "question": "list.stream().filter(x -> x > 0).map(x -> x * 2); כתוב אבל התוצאה הוא לעולם נקבע לתוך terminal פעולה כמו .collect() או .forEach(). מה בעצם קורה כלשהו קו זה רץ?",
          "options": [
            {
              "icon": "",
              "label": "כלום קורה כדי הרשימה של אלמנטים בכלל — filter ו-map הם עצלן middle פעולות שרק בנות עד עיירה תיאור; ללא terminal פעולה, כלום של זה כל זמן בעצם רץ"
            },
            {
              "icon": "",
              "label": "כל אלמנט הוא מסוננת וממופה באופן מיידי, בדיוק כמו אם terminal פעולה היא קרא"
            },
            {
              "icon": "",
              "label": "רק ה-filter רץ באופן מיידי; map הוא deferred עד terminal פעולה מופיע"
            },
            {
              "icon": "",
              "label": "זה זורק IllegalStateException, כי stream עיירה דורש terminal פעולה כדי קומפיל"
            }
          ]
        }
      ],
      "optionOrderVersion": "0154f9576054ad6f"
    }
  }
}
