JavaRush /בלוג Java /Random-HE /חריגים בג'אווה
Roman
רָמָה

חריגים בג'אווה

פורסם בקבוצה
כשנתקלתי בנושא "חריגים" עלו שאלות רבות שעליהן נאלצתי לחפש תשובות בפינות שונות באינטרנט כדי להבין לפרטי פרטים איך הכל עובד. כתוצאה מכך, ריכזתי הסבר משלי, שעשוי להיות מובן יותר למתחילים שזה עתה נתקלו בתופעה זו. חריגים בג'אווה - 1במחשבים, פסיקה היא אות נכנס למעבד שמתרחש אירוע הדורש תגובה מיידית. אות פסיק מחייב את המעבד להשהות תוכנית פועלת כדי שניתן יהיה להמשיך אותה מעט מאוחר יותר, כלומר, המחשב חייב לזכור את כל המידע הקשור לביצוע התוכנית. הפרעות כאלה הן זמניות, אם לא קטלניות. הפרעות כאלה יכולות להיגרם על ידי קוד תוכנית או על ידי פונקציונליות חומרה כלשהי (לדוגמה, פשוט לחיצה על מקשים במקלדת; טיימרים, למשל, לכיבוי אוטומטי של המחשב). מספר ההפרעות מוגבל למספר מסוים, המובנה בייצור של מעבד מסוים, כלומר, מוקצים "ערוצי" תקשורת מיוחדים לכך, המאפשרים לך לגשת למעבד תוך עקיפת כל שאר התהליכים. פסיקות נוצרות אוטומטית גם כאשר מתרחשת שגיאה בקוד התוכנית המבצעת (לדוגמה, אם מתרחשת חלוקה באפס). הפרעות כאלה נקראות באופן מסורתי מלכודות או חריגים . במקרים כאלה נהוג לומר: "הושלך חריג", כלומר הופעלה חריג או הושלך (נזרק) חריג , כלומר בקשה לפסיקה.עם השאלה "מה לעשות?" נשלח למעבד. ברגע זה, המעבד מפסיק לעבוד, זוכר את הנקודה שבה הוא נעצר, או ליתר דיוק את האשכול של התא הבא, שממנו יש לבצע את המידע. כל שרשרת ההוראות שבוצעו ולא בוצעו זכורה. לאחר מכן, המעבד קורא הוראות מהזיכרון לפעולה במקרה של שגיאה כזו. בהתאם להוראה זו, הוא יכול להזין ערכים חדשים לתוך אשכולות מסוימים, להוסיף כמה שרשראות של פעולות או מחזור חדש (לדוגמה, מחזור החזרה או לולאה) וכו', כלומר, בהתאם לשגיאה שהונחה קודם לכן הוראות למטה מבוצעות. במערכת המחשוב עצמה מובנות בתוכה פסיקות אוטומטיות רבות, המופעלות לאחר פרק זמן מסוים, למשל, כדי לשלוט בתהליכים הפועלים במחשב או להפעיל אזעקות מוגדרות, לאסוף אותות חיצוניים נכנסים וממירי נתונים שונים. כדאי לזכור שמספר רב של פסיקות, ממספר סיבות, יכולות "לתלות" את המערכת לחלוטין. שגיאה בקוד התוכנית תגרום אוטומטית להפרעה במעבד, אותה הוא ינסה לעבד בהתאם להוראות שנקבעו. אבל לא כל ההפרעות נועדו לטפל בהן, או שהיא עשויה לייצר הליך שלא מתאים לנו, למשל, היא פשוט תקרוס את האפליקציה. לכן, בתכנות, אפשר לארגן פסיקה משלך עבור קטע מסוים של קוד שבו המתכנת יכול לראות אפשרות של שגיאה. במקרה זה, השגיאה תעובד בתוך התוכנית ולא תיצור קשר עם המעבד לקבלת הוראות עיבוד. ההגדרה של בלוקים כאלה מאורגנת על ידי יצירת אובייקט "חריג" . אובייקט זה נוצר באופן אוטומטי בבלוק try-catch. החסימה >tryנבדקת עבור נוכחות של שגיאה, ואם יש כזו, התוכנית עוברת לבלוק catch, שם ננקטות פעולות כדי למנוע או לתקן את השגיאה. לדוגמה, אם נזין מספרים מהמקלדת , שאותם יש להוסיף ולגרוע לאחר מכן, אז הזנת אותיות מהמקלדת לא תאפשר להוסיף אותם עם מספרים (בואו נסמן את סכום שני המשתנים הללו באות S). לכן, כצוות, tryעלינו לבדוק האם ניתן להוסיף מספר A, המכיל מספרים, למספר B, המכיל אותיות (כלומר, S = A + B), ואם זה לא אפשרי, וזה בלתי אפשרי, אז בטוח יש לנקוט באמצעים כך שגיאות זה לא קרה ופסיקה חדשה עם השאלה "מה לעשות?" לא תעוף למעבד. אם אין חריגה בתוכנית, ביצועה יופסק על ידי המעבד. אם יש Exception, כאשר הוא "נתפס" על ידי הפקודה try, השליטה עוברת לפקודה catch, שיכולה להגדיר פתרון חלופי, למשל, לא נוסיף את שני המספרים הללו, אלא נציב S = A.

int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 } catch (Exception igogo1) {
   S = a;
 }
 return S;
/* מחרוזת "int r = 1;" אינו מבוצע מכיוון שהתרחשה שגיאה והתוכנית מפנה את העבודה ישירות למטפל החריגים (catch block*/ לפיכך, הנוכחות של Exceptions היא הזדמנות לפתור את הבעיה בתוך התוכנית מבלי לזרוק אותה לרמת המעבד. האובייקט "חריגה", שנוצר אוטומטית בבלוק tryכאשר מתגלה שגיאה, מכיל את הערך של סוג השגיאה. בואו נקרא לזה "החריגה שלנו" - למקרה הספציפי שלנו עם תיאור של השגיאה הספציפית שלנו. יוצרי שפת ג'אווה יצרו מראש רשימה מסוימת של שגיאות אופייניות ואפשרויות אופייניות לתיקון שלהן, כלומר ב-java יש ספריה מסוימת של חריגים , אליה נוכל לפנות כדי לטפל בשגיאה שהתרחשה, כך לא לכתוב את קוד העיבוד בעצמנו ולכן סביר להניח ש-OurException כבר תואר מישהו, אז אנחנו רק צריכים לדעת את השם של איזה מהחריגים האלה להכניס לתוכנית שלנו כדי לטפל בקוד שבו עלול להתרחש כשל. אם נעשה טעות ונבחר חריגה שגויה מהספרייה , המטפל לא "יתפוס" אותה, השגיאה לא תמצא פתרון בתוך התוכנית והבקשה תישלח למעבד. אבל יש דרך לעצלנים. אם איננו יודעים את השם של החריג שאנו צריכים מהספרייה, נוכל לקחת את השם הכללי עם השם " חריגה ", כמו בדוגמה שתוארה לעיל. חריגה זו מסוגלת לטפל בכל סוג של שגיאה, אך היא אינה מסוגלת לספק מידע ספציפי על האירוע שנוכל לרשום. ספריית החריגים שנכתבו בעבר מורכבת מחריגים מסומנים ובלתי מסומנים . אלה שניתנים לסימון הם אלו שניתן לתקן מבלי להפריע לעבודת התוכנה, כלומר, אם ננסה לפתוח קובץ בתיקייה בה הוא לא קיים, המערכת תודיע לנו על כך, נוכל להוריד את הקובץ לתוך התיקיה הרצויה והמשך בתוכנית. כלומר, למעשה, נשלחה בקשה להפרעה למעבד , אך ללא השאלה: "חפש מה לעשות בבעיה הזו?!?!" שלחנו Interrupt, אותה זיהינו בעצמנו, עם הוראה מוכנה, אותה עיבד המעבד והמשיך בביצוע התוכנית. לא מסומנים אותן שגיאות שלא ניתן לתקן והתוכנית תיסגר לפני השלמתה, כלומר תישלח בקשת פסיקה למעבד, שבכל מקרה יפריע לביצוע התוכנית. הנקודה היחידה בכתיבת חריגים כאלה בתוכנית היא לתת למשתמש להבין מה קרה, שכן לאחר שתפסנו את ההפרעה הזו, אנו יכולים להציג הודעת מידע על המסך, וזו הסיבה שהתוכנית קרסה. הסיבה השנייה לתפוס הפרעות כאלה היא היכולת לתעד אותן ביומנים לצורך ניתוח עוקב (פרצו לך, אבל לפחות אתה יודע איפה). תוצאה של נוכחותן של ספריות כאלה היא הצורך לזכור לכלול אותן. (רשימה של חריגים מסומנים ובלתי מסומנים עם ספריות ניתן למצוא, למשל, כאן ) אם אנחנו לא יודעים בדיוק איזו ספרייה לכלול או שיש מספר אפשרויות שגיאה, אז נוכל catchלפרט את החריגים הנדרשים בכמה. המערכת עצמה תבחר את המטפל הנכון אם הוא ברשימה. במקום חריג ספציפי, אתה יכול לכתוב " חריג " כללי שיכול להתמודד עם כל סוג של חריגה אם הוא לא עובד בבלוקים קודמים.

int a = 4;
String b = “hello”;
int S = 0;
 try {
   S = a + b;
   int r = 1;
 } 
catch(NullPointerException blabla2) {
   System.out.println("Exception handling code for the NullPointerException.");
 } 
catch (ArithmeticException ex1) {
   S = a;
 }
catch(Exception uups1) {
   System.out.println("Exception occured");
 } 
 return S;
אם יש חסימה, tryנוצרת חריגה אוטומטית. אם אנחנו צריכים לכפות חריגה בנקודת זמן כלשהי , אזי נעשה שימוש בפקודה throw. כלומר, אנו יוצרים באופן עצמאי אובייקט new throw... שלאחריו, התוכנית מפסיקה את עבודתה, שולחת בקשת Interrupt למעבד ומועברת למדור התוכנית catch, משם היא מנסה לקבל הוראות לפעולות נוספות. על ידי יצירה ידנית של חריגה , נוכל לציין את הסוג הספציפי שלו מהספרייה:

throw new ArithmeticException("Access denied - You must be at least 18 years old.");
אז המטפל יחפש בלוק catchעם החריג הספציפי הזה - חפש בכל התוכנית, מכל הצדדים catch. לאחר throwפקודת הטיפול בחריגים, כל קוד התוכנית שנותר לא יבוצע, מלבד זה שנמצא בבלוק catch. אם המטפל לא נמצא בתוכנית, המעבד נשאל את השאלה: "תחליט בעצמך מה לעשות" וזה מפריע לתוכנית. השיחה new throw... יכולה להתבצע גם בתוך >tryהבלוק וגם מחוצה לו (בכל מקום בתוכנית)

try {
   /* функция or действие, в котором есть сомнения. То есть: «попробуй выполнить это, а если не получится, а, если не получится, запускай режим исключения» */
   throw new CallForException(); /* Назначаем исключение, которое будет работать в случае наличия ошибки в функции, описанной выше. Здесь исключение «CallForException» - берется из библиотеки существующих исключений */
} catch (CallForException ee1) {
   /* Корректируем ошибку, чтобы программа не «отвалилась» or выводим сообщение об ошибке or что-то ещё */
} finally {
   /* этот блок работает всегда независимо от того была ошибка or нет. А если была, то сработало ли решение в catch or нет */
   /* часто используется для подчистки хвостов, например, для закрытия запущенного file or базы данных */
   /* в ряде случаев блок catch вообще может быть опущен и оставлен только блок finally и наоборот finally может быть опущен и оставлен только catch */
   /* Не допускается использование этого блока в ряде случаев, например, когда функция System.exit() запущена or другие системные Исключения, типа «отключение электроэнергии» и т.п. */
}

הודעה על חריגים

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

public void createFile(String path, String text) throws IOException {
    FileWriter writer = new FileWriter(path, true);
    writer.write(text);
    writer.close();
}
אבל יחד עם זאת, אין מטפל עצמו, מה שאומר שכעת לא נוכל פשוט לקרוא למתודה הכתובה בתוכנית שלנו במצב רגיל. כעת עלינו לכתוב מטפל בשגיאות ולקרוא לשיטה הזו בבלוק try:

String filePath = "hello.txt";
String text = "Hello World";
 
try {
    createFile(filePath, text);
} catch (IOException ex) {
    System.err.println("Error creating file: " + ex);
}

חריגים מקומיים

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

public class StudentNotFoundException extends Exception {
 
    public StudentNotFoundException (String message) {
        super(message);
    }
}
יש לזכור שני כללים בעת יצירת חריגים משלך:
  1. שם הכיתה שלנו חייב להסתיים ב"חריגה"
  2. המחלקה חייבת להכיל בנאי עם משתנה מחרוזת המתאר את הפרטים של בעיית ה-Exception. בבנאי קוראים לבנאי העל ומועברת הודעה.
דוגמה לשימוש בחריג שנוצר:

public class StudentManager { 
    public Student find(String studentID) throws StudentNotFoundException {
        if (studentID.equals("123456")) {
            return new Student();
        } else {
            throw new StudentNotFoundException(
                "Could not find student with ID " + studentID);
        }
    }
}
אנו תופסים את החריג הזה עם הקוד:

public class StudentTest {
    public static void main(String[] args) {
        StudentManager manager = new StudentManager();
         try { 
            Student student = manager.find("0000001");
        } catch (StudentNotFoundException ex) {
            System.err.print(ex);
        }
    }
}
התוצאה של הפעלת התוכנית תהיה: StudentNotFoundException: לא ניתן היה למצוא סטודנט עם תעודת זהות 0000001

למה אתה צריך לכתוב חריגים?

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

הפניות:

הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION