CodeGym /בלוג Java /Random-HE /חריגים בג'אווה
John Squirrels
רָמָה
San Francisco

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

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

מהו חריג ג'אווה?

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

כמה מילים על מילות מפתח

טיפול בחריגים ב-Java מבוסס על השימוש במילות המפתח הבאות בתוכנית:
  • try - מגדיר גוש קוד שבו יכול להתרחש חריג;
  • catch - מגדיר גוש קוד שבו מטופלים חריגים;
  • לבסוף - מגדיר בלוק קוד אופציונלי שאם קיים, מבוצע ללא קשר לתוצאות של בלוק try.
מילות מפתח אלו משמשות ליצירת מבנים מיוחדים בקוד: נסה{}תפוס , נסה{}תפוס{}סוף סוף , נסה{}סוף סוף{} .
  • throw - משמש להעלאת חריג;
  • throws - משמש בחתימת השיטה כדי להזהיר שהשיטה עשויה לזרוק חריג.
דוגמה לשימוש במילות מפתח בתוכנית Java:
// This method reads a string from the keyboard

public String input() throws MyException { // Use throws to warn
// that the method may throw a MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// We use a try block to wrap code that might create an exception. In this case,
// the compiler tells us that the readLine() method in the
// BufferedReader class might throw an I/O exception
    try {
        s = reader.readLine();
// We use a catch block to wrap the code that handles an IOException
    } catch (IOException e) {
        System.out.println(e.getMessage());
// We close the read stream in the finally block
    } finally {
// An exception might occur when we close the stream if, for example, the stream was not open, so we wrap the code in a try block
        try {
            reader.close();
// Handle exceptions when closing the read stream
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// We've decided that an empty string will prevent our program from working properly. For example, we use the result of this method to call the substring(1, 2) method. Accordingly, we have to interrupt the program by using throw to generate our own MyException exception type.
        throw new MyException("The string cannot be empty!");
    }
    return s;
}

למה אנחנו צריכים חריגים?

בואו נסתכל על דוגמה מהעולם האמיתי. תארו לעצמכם שבקטע של כביש מהיר יש גשר קטן עם יכולת משקל מוגבלת. אם מכונית כבדה מהמגבלה של הגשר נוסעת מעליה, היא עלולה לקרוס. המצב של הנהג יהפוך, בלשון המעטה, לחריג. כדי להימנע מכך, מחלקת התחבורה מתקינה שלטי אזהרה על הכביש לפני שמשהו ישתבש. כשהוא רואה את תמרור האזהרה, נהג משווה את משקל הרכב שלו למשקל המרבי לגשר. אם הרכב כבד מדי, הנהג נוסע במסלול עוקף. אגף התחבורה, ראשית, איפשר לנהגי משאיות לשנות את מסלולם במידת הצורך, שנית, הזהיר את הנהגים מפני הסכנות בכביש הראשי, ושלישית, הזהיר את הנהגים כי אסור להשתמש בגשר בתנאים מסוימים. חריגים בג'אווה - 2היכולת למנוע ולפתור מצבים חריגים בתוכנית, ולאפשר לה להמשיך לרוץ, היא אחת הסיבות לשימוש בחריגים ב-Java. מנגנון החריגה מאפשר לך גם להגן על הקוד שלך (API) מפני שימוש לא תקין על ידי אימות (בדיקת) כל קלט. עכשיו דמיינו שאתם מחלקת התחבורה לשנייה. ראשית, אתה צריך לדעת את המקומות שבהם נהגים יכולים לצפות לצרות. שנית, עליך ליצור ולהתקין שלטי אזהרה. ולבסוף, אתה צריך לספק מעקפים אם מתעוררות בעיות במסלול הראשי. ב-Java, מנגנון החריגה פועל בצורה דומה. במהלך הפיתוח, אנו משתמשים ב- try block כדי לבנות "מחסומי חריגה" סביב קטעי קוד מסוכנים, אנו מספקים "נתיבי גיבוי" באמצעות בלוק catch {} , ואנחנו כותבים קוד שאמור לרוץ לא משנה מה בבלוק סופית {} . אם אין באפשרותנו לספק "מסלול גיבוי" או שאנו רוצים לתת למשתמש זכות בחירה, עלינו לפחות להזהיר אותו מפני הסכנה. למה? רק תארו לעצמכם את זעמו של נהג שמבלי לראות תמרור אזהרה אחד מגיע לגשר קטן שהוא לא יכול לחצות! בתכנות, כשכותבים את השיעורים והשיטות שלנו, אנחנו לא תמיד יכולים לחזות כיצד הם עשויים לשמש מפתחים אחרים. כתוצאה מכך, איננו יכולים לחזות את הדרך הנכונה ב-100% לפתור מצב חריג. עם זאת, זו צורה טובה להזהיר אחרים מפני אפשרות של מצבים חריגים. מנגנון החריגה של Java מאפשר לנו לעשות זאת עם מילת המפתח throws - בעצם הצהרה שההתנהגות הכללית של השיטה שלנו כוללת זריקת חריג. לפיכך, כל מי שמשתמש בשיטה יודע שעליו לכתוב קוד כדי לטפל בחריגים.

מזהיר אחרים מפני "צרות"

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

היררכיית חריגים

כאשר מתרחשת שגיאה בזמן שתוכנית פועלת, ה-JVM יוצר אובייקט מהסוג המתאים מהיררכיית החריגים של Java - קבוצה של חריגים אפשריים שמקורם באב קדמון משותף - המחלקה Throwable . אנו יכולים לחלק מצבי זמן ריצה חריגים לשתי קבוצות:
  1. מצבים שמהם התוכנית לא יכולה להתאושש ולהמשיך בפעולה רגילה.
  2. מצבים שבהם התאוששות אפשרית.
הקבוצה הראשונה כוללת מצבים הכוללים חריג שמקורו במחלקת השגיאה . אלו הן שגיאות המתרחשות עקב תקלה ב-JVM, גלישת זיכרון או כשל במערכת. הם בדרך כלל מצביעים על בעיות חמורות שלא ניתן לתקן באמצעות תוכנה. ב-Java, האפשרות של חריגים כאלה לא נבדקת על ידי המהדר, ולכן הם ידועים בתור חריגים לא מסומנים. קבוצה זו כוללת גם RuntimeExceptions, שהם חריגים שיורדים מהמחלקה Exception ונוצרים על ידי ה-JVM בזמן הריצה. הם נגרמים לרוב משגיאות תכנות. חריגים אלה גם אינם מסומנים (לא מסומנים) בזמן ההידור, כך שאינך נדרש לכתוב קוד כדי לטפל בהם. הקבוצה השנייה כוללת מצבים חריגים שניתן לצפות מראש בעת כתיבת התוכנית (ולכן עליך לכתוב קוד כדי לטפל בהם). חריגים כאלה נקראים חריגים מסומנים. כשזה מגיע לחריגים, רוב העבודה של מפתח Java היא טיפול במצבים כאלה.

יצירת חריגה

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

טיפול בחריגים

ב-Java, אנו יוצרים בלוקי קוד שבהם אנו צופים את הצורך בטיפול בחריגים באמצעות המבנים try{}catch , try{}catch{}finally , and try{}finally{} . חריגים בג'אווה - 4כאשר חריג נזרק בבלוק ניסיון , ה-JVM מחפש מטפל חריג מתאים בבלוק ה-catch הבא . אם לבלוק תופס יש את המטפל החריגים הנדרש, השליטה עוברת אליו. אם לא, אז ה-JVM מסתכל בהמשך שרשרת בלוקי התפיסה עד שנמצא המטפל המתאים. לאחר ביצוע בלוק תפוס , השליטה מועברת לבלוק הסופי האופציונלי . אם לא נמצא בלוק תפוס מתאים , אז JVM עוצר את התוכנית ומציג את מעקב המחסנית (מחסנית קריאות השיטה הנוכחית), לאחר ביצוע תחילה את הבלוק הסופי אם הוא קיים. דוגמה לטיפול בחריגים:
public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside print method: " + s);
    }

    public static void main(String[] args) {
        Print print = new Print();
        List list= Arrays.asList("first step", null, "second step");

        for (String s : list) {
            try {
                print.print(s);
            }
            catch (NullPointerException e) {
                System.out.println(e.getMessage());
                System.out.println("Exception handled. The program will continue");
            }
            finally {
                System.out.println("Inside finally block");
            }
            System.out.println("The program is running...");
            System.out.println("-----------------");
        }

    }
    }
להלן תוצאות השיטה העיקרית :
Inside print method: first step
Inside finally block
The program is running...
-----------------
Exception: s is null!
Exception handled. The program will continue
Inside finally block
The program is running...
-----------------
Inside print method: second step
Inside finally block
The program is running...
-----------------
הסוף משמש בדרך כלל לסגירת זרמים ולשחרר כל משאבים שנפתחו/מוקצים בבלוק ניסיון . עם זאת, בעת כתיבת תוכנית, לא תמיד ניתן לעקוב אחר סגירת כל המשאבים. כדי להקל על חיינו, מפתחי Java מציעים את מבנה ה- try-with-resources , אשר סוגר אוטומטית כל משאב שנפתח בבלוק ניסיון . ניתן לשכתב את הדוגמה הראשונה שלנו עם נסה עם משאבים :
public String input() throws MyException {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
        s = reader.readLine();
   } catch (IOException e) {
       System.out.println(e.getMessage());
   }
    if (s.equals("")) {
        throw new MyException ("The string cannot be empty!");
    }
    return s;
}
הודות ליכולות Java שהוצגו בגרסה 7, אנו יכולים גם לשלב לכידת חריגים הטרוגניים לבלוק אחד, מה שהופך את הקוד לקומפקטי וקריא יותר. דוגמא:
public String input() {
    String s = null;
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
        s = reader.readLine();
        if (s.equals("")) {
            throw new MyException("The string cannot be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

בשורה התחתונה

שימוש בחריגים ב-Java מאפשר לך להפוך את התוכניות שלך לחזקות יותר על ידי יצירת "נתיבי גיבוי", השתמש בלוקים מסוג catch כדי להפריד את הקוד הראשי מקוד הטיפול בחריגים, והשתמש ב-throws כדי להעביר את האחריות לטיפול בחריגים למי שמשתמש בשיטה שלך .
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION