היררכיית מחלקות החריגות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 59 מתוך 87.
מערכת הטיפול בחריגות של Java בנויה על היררכיית מחלקות מאורגנת היטב, שבבסיסה נמצאת המחלקה Throwable. הבנת ההיררכיה הזו עוזרת לך ללכוד חריגות ולטפל בהן ביעילות רבה יותר.
בראש נמצאת Throwable, מחלקת האב של כל החריגות והשגיאות. יש לה שתי תת־מחלקות ישירות:
Throwable
├── Error // בעיות חמורות (אל תתפסו אותן)
└── Exception // בעיות שניתן להתאושש מהן
└── RuntimeException // חריגות שלא נבדקותשגיאה מייצגת בעיות חמורות שיישומים לא אמורים לנסות לטפל בהן, כמו OutOfMemoryError או StackOverflowError. אלה מצביעות על בעיות יסודיות ב-JVM עצמו.
חריגה היא הענף שתעבוד איתו הכי הרבה. הוא מתחלק לשתי קטגוריות: חריגות בדוקות (מחלקות משנה ישירות של Exception) וחריגות לא בדוקות (מחלקות משנה של RuntimeException).
// מחלקות חריגה נפוצות
Exception
├── IOException // בעיות בקבצים או ברשת
├── SQLException // בעיות במסד הנתונים
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionמכיוון שחריגות הן מחלקות, הן פועלות לפי כללי הורשה. כשאתם תופסים סוג של חריגת־אב, אתם תופסים גם את כל חריגות־הצאצא שלה:
try {
// קוד כלשהו
} catch (Exception e) {
// תופס את כל החריגות (בדרך כלל רחב מדי)
}try {
// קוד כלשהו
} catch (RuntimeException e) {
// תופס רק חריגות בזמן ריצה ותתי־מחלקות שלהן
}ההיררכיה הזו מאפשרת לך להיות ספציפי או כללי ככל שנדרש בעת טיפול בשגיאות, והיא הבסיס ליצירת חריגות מותאמות אישית משלך.
אתגר
קלבואו נבנה מנתח חריגות שמדגים כיצד היררכיית החריגות של Java פועלת בפועל! תיצרו מערכת שתופסת חריגות ברמות שונות של ספציפיות ומדווחת איזה סוג נתפס.
תארגנו את הקוד שלכם בשלושה קבצים:
ExceptionThrower.java: צרו מחלקה שיכולה להשליך סוגים שונים של חריגות בהתאם לקלט. המחלקה שלכם צריכה לכלול שלוש מתודות סטטיות:triggerRuntime(String type)- בהתאם למחרוזת הסוג, השליכו חריגות זמן ריצה שונות:- אם type הוא
"null", השליכוNullPointerExceptionעם ההודעה"Null value encountered" - אם type הוא
"index", השליכוArrayIndexOutOfBoundsExceptionעם ההודעה"Invalid index" - אם type הוא
"argument", השליכוIllegalArgumentExceptionעם ההודעה"Bad argument"
triggerArithmetic()- השליכוArithmeticExceptionעם ההודעה"Division error"triggerGeneric()- השליכוIllegalStateExceptionעם ההודעה"Generic runtime error"(ההיררכיה שלה היא Exception > RuntimeException > IllegalStateException)- אם type הוא
ExceptionAnalyzer.java: צרו מחלקה שתופסת חריגות ברמות שונות בהיררכיה ומזהה מה נתפס. כללו את המתודות הסטטיות הבאות:analyzeSpecific(String type)- קראו ל-ExceptionThrower.triggerRuntime(type)בתוך בלוק try. השתמשו בבלוקי catch נפרדים עבורNullPointerException,ArrayIndexOutOfBoundsExceptionו-IllegalArgumentException. עבור כל אחד מהם, הדפיסו:Caught specific: [exception class simple name]ואחריוMessage: [exception message]analyzeWithParent()- קראו ל-ExceptionThrower.triggerArithmetic()בתוך בלוק try. תפסו אותה באמצעותRuntimeException(סוג האב). הדפיסו:Caught via parent: RuntimeExceptionואחריוActual type: [exception class simple name]analyzeWithGrandparent()- קראו ל-ExceptionThrower.triggerGeneric()בתוך בלוק try. תפסו אותה באמצעותException(רמה גבוהה יותר בהיררכיה). הדפיסו:Caught via grandparent: ExceptionואחריוActual type: [exception class simple name]Main.java: חברו יחד את מנתח החריגות שלכם! תקבלו קלט אחד: מחרוזת מסוג חריגה (או"null","index"או"argument").תחילה, הדפיסו
=== Specific Catch ===וקראו ל-analyzeSpecificעם הקלט שלכם.לאחר מכן הדפיסו שורה ריקה,
=== Parent Catch ===, וקראו ל-analyzeWithParent.לבסוף, הדפיסו שורה ריקה,
=== Grandparent Catch ===, וקראו ל-analyzeWithGrandparent.
תקבלו קלט אחד: סוג החריגה שיש להשליך ("null", "index" או "argument").
השתמשו ב-e.getClass().getSimpleName() כדי לקבל את שם המחלקה של החריגה וב-e.getMessage() כדי לקבל את ההודעה שלה. האתגר הזה מדגים שתפיסת סוג חריגה של מחלקת אב תופסת גם את כל המחלקות הצאצאיות שלה: זהו מושג מרכזי כשמחליטים עד כמה הטיפול בחריגות שלכם צריך להיות ספציפי!
נסו בעצמכם
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String type = scanner.nextLine();
// TODO: הדפס את "=== Specific Catch ===" וקרא ל-ExceptionAnalyzer.analyzeSpecific(type)
// TODO: הדפס שורה ריקה, לאחר מכן את "=== Parent Catch ===", ואז קרא ל-ExceptionAnalyzer.analyzeWithParent()
// TODO: הדפס שורה ריקה, לאחר מכן את "=== Grandparent Catch ===", ואז קרא ל-ExceptionAnalyzer.analyzeWithGrandparent()
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותשדות (מאפיינים)מתודת הבנאיהעמסת בנאיםחזרה – מחשבון פשוט4ירושה
ירושה בסיסית (extends)מילת המפתח superדריסת מתודות (@Override)שרשור בנאיםהמחלקה Objectירושה יחידה ורב־רמתיתלמה אין ירושה מרובה של מחלקותסיכום – היררכיית עובדים7מתודות מיוחדות ומחלקת Object
מתודת toString()equals() ו-hashCode()מתודת clone()compareTo() ו-Comparableהממשק Comparatorסיכום – מיון מותאם אישית10טיפול בחריגות ב-OOP
היררכיית מחלקות החריגותחריגות מותאמות אישיתשגיאות Checked לעומת Uncheckedתבנית Try With Resourcesחזרה – משתמש מאומת2מצייני גישה ואנקפסולציה
סקירה של רמות הגישהמתודות Getter ו-Setterהסתרת מידעמילת המפתח finalסיכום – מנהל חשבון בנק5פולימורפיזם
יסודות העמסת מתודותדריסת מתודות (בזמן ריצה)המרה כלפי מעלה וכלפי מטההאופרטור instanceofמחלקות ומתודות מופשטותסיכום – מחשבון צורות8מושגי OOP מתקדמים
הרכבה מול ירושהאגרגציה מול הרכבהמחלקות פנימיות, מקוננות ואנונימיותEnums ומתודות של EnumRecords (Java 16+)מחלקות חתומות (Java 17+)3מאפייני מחלקה וחברים סטטיים
משתני מופע לעומת משתנים סטטייםמתודות סטטיותבלוקים סטטייםקבועים (static final)סיכום — מונה ומחלקת עזר6ממשקים ומחלקות מופשטות
מבוא לממשקיםמימוש ממשקיםמימוש של כמה ממשקיםמתודות ברירת מחדל וסטטיות בממשקמחלקות מופשטות לעומת ממשקיםממשקים פונקציונלייםסיכום – מערכת תשלומיםתרגלו בעצמכם: קומפיילר Java אונליין