שגיאות Checked לעומת Unchecked
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 61 מתוך 87.
ראית שהיררכיית החריגות של Java מתפצלת לענפים שונים. ההבחנה המרכזית שעליך להבין היא בין חריגות בדוקות לחריגות לא בדוקות. הדבר משפיע על האופן שבו עליך לטפל בהן בקוד שלך.
חריגות בדוקות הן חריגות שהמהדר מחייב אותך לטפל בהן. הן יורשות ישירות מ־Exception (לא דרך RuntimeException). עליך לתפוס אותן או להצהיר עליהן באמצעות throws:
// חובה לטפל ב-IOException - זו חריגה שנבדקת בזמן הידור
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // עלול לזרוק IOException
}
// או לתפוס אותה
public void readFileSafe(String path) {
try {
FileReader reader = new FileReader(path);
} catch (IOException e) {
System.out.println("File error: " + e.getMessage());
}
}חריגות לא בדוקות יורשות מ־RuntimeException. המהדר לא דורש ממך לטפל בהן. בדרך כלל הן מצביעות על שגיאות תכנות כמו הפניות null או גישה לא חוקית למערך:
// אין צורך בהצהרת throws
public int divide(int a, int b) {
return a / b; // עלול לזרוק ArithmeticException (חריגה לא בדוקה)
}
String name = null;
name.length(); // NullPointerException (חריגה לא בדוקה)כשיוצרים חריגות מותאמות אישית, בחרו את מחלקת האב בהתאם לאופן שבו אתם רוצים שהקוראים יטפלו בהן. השתמשו בחריגות מסומנות עבור מצבים שניתן להתאושש מהם ושעל הקוראים לצפות להם. השתמשו בחריגות לא מסומנות עבור שגיאות תכנות שלא אמורות להתרחש בקוד תקין.
אתגר
קלבואו נבנה מערכת לאימות גיל שתדגים את ההבדל המרכזי בין חריגות בדוקות לחריגות לא־בדוקות! תיצרו חריגות מותאמות אישית משני הסוגים ותראו כיצד המהדר מתייחס אליהן באופן שונה.
תארגנו את הקוד שלכם בארבעה קבצים:
InvalidAgeException.java: צרו חריגה בדוקה עבור כשלים באימות גיל. החריגה צריכה לרשת ישירות מ־Exception, כלומר הקוראים יהיו חייבים לטפל בה. כללו בנאי שמקבל הודעה ומעביר אותה למחלקת האב.NegativeAgeException.java: צרו חריגה לא־בדוקה למקרה שמישהו מספק גיל שלילי (שגיאת תכנות שלא אמורה להתרחש עם קלט תקין). החריגה צריכה לרשת מ־RuntimeException. כללו בנאי שמקבל הודעה ומעביר אותה למחלקת האב.AgeVerifier.java: צרו מחלקה שמאמתת גילאים באמצעות שני סוגי החריגות. כללו שתי מתודות סטטיות:verifyAge(int age)- המתודה צריכה לזרוקNegativeAgeException(לא־בדוקה) עם ההודעה"Age cannot be negative: [age]"אם הגיל קטן מ־0. אם הגיל קטן מ־18, זרקוInvalidAgeException(בדוקה) עם ההודעה"Must be 18 or older: [age]". אחרת, הדפיסוAge [age] verified successfully. מכיוון שהמתודה הזו זורקת חריגה בדוקה, עליכם להצהיר עליה באמצעותthrows InvalidAgeException.verifyAgeUncheckedOnly(int age)- המתודה הזו משתמשת רק בחריגות לא־בדוקות. אם הגיל שלילי, זרקוNegativeAgeExceptionבאותו פורמט של הודעה. אם הגיל קטן מ־18, זרקוIllegalArgumentExceptionעם ההודעה"Too young: [age]". אחרת, הדפיסוAge [age] verified (unchecked method). שימו לב שהמתודה הזו אינה זקוקה להצהרתthrows!Main.java: חברו יחד את מערכת האימות שלכם! תקבלו קלט אחד: גיל (מספר שלם).ראשית, הדפיסו
=== Checked Exception Method ===וקראו ל־verifyAgeעם הגיל שהתקבל בקלט. מכיוון שהיא זורקת חריגה בדוקה, עליכם לעטוף אותה ב־try-catch. תפסו אתInvalidAgeExceptionוהדפיסוChecked exception caught: [message]. תפסו גם אתNegativeAgeExceptionוהדפיסוUnchecked exception caught: [message].לאחר מכן, הדפיסו שורה ריקה ואת
=== Unchecked Exception Method ===. קראו ל־verifyAgeUncheckedOnlyעם אותו גיל. אף על פי שהמתודה הזו יכולה לזרוק חריגות, אינכם חייבים לתפוס אותן. עם זאת, עטפו אותה ב־try-catch בכל זאת, כדי לטפל בשגיאות באופן מסודר. תפסו אתNegativeAgeExceptionוהדפיסוRuntime exception caught: [message]. תפסו אתIllegalArgumentExceptionוהדפיסוIllegal argument caught: [message].
תקבלו קלט אחד: מספר שלם שמייצג את הגיל שיש לאמת.
שימו לב להבדל המרכזי: המתודה עם החריגה הבדוקה מחייבת הצהרת throws וכופה על הקוראים לטפל בה, ואילו המתודה עם החריגה הלא־בדוקה מתקמפלת היטב ללא טיפול בחריגות. זהו ההבדל הבסיסי בין חריגות בדוקות לחריגות לא־בדוקות ב־Java!
נסו בעצמכם
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int age = scanner.nextInt();
// TODO: בדקו את המתודה של החריגה הנבדקת
// הדפיסו: "=== Checked Exception Method ==="
// קראו ל-AgeVerifier.verifyAge(age) בתוך try-catch
// - תפסו את InvalidAgeException: הדפיסו "Checked exception caught: [message]"
// - תפסו את NegativeAgeException: הדפיסו "Unchecked exception caught: [message]"
// TODO: הדפיסו שורה ריקה, ואז "=== Unchecked Exception Method ==="
// קראו ל-AgeVerifier.verifyAgeUncheckedOnly(age) בתוך try-catch
// - תפסו את NegativeAgeException: הדפיסו "Runtime exception caught: [message]"
// - תפסו את IllegalArgumentException: הדפיסו "Illegal argument caught: [message]"
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
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 אונליין