JavaRush /בלוג Java /Random-HE /חריגים בג'אווה (חריגים ב-Java)

חריגים בג'אווה (חריגים ב-Java)

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

מה הם חריגים java

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

בקצרה על מילות המפתח לנסות, לתפוס, לבסוף, זורק

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

public String input() throws MyException {//warn with throws,
// that the method can throw MyException
      BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String s = null;
// in the try block we enclose the code in which an exception can occur, in this
// if the compiler tells us that the readLine() method of the class
// BufferedReader may throw an I/O exception
    try {
        s = reader.readLine();
// in the catch block we enclose the code for handling the IOException exception
    } catch (IOException e) {
        System.out.println(e.getMessage());
// close the read stream in the finally block
    } finally {
// when closing the stream, an exception is also possible, for example, if it was not opened, so we “wrap” the code in a try block
        try {
            reader.close();
// write exception handling when closing the read stream
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    if (s.equals("")) {
// we decided that an empty string could disrupt the work of our program in the future, for example, on the result of this method, we need to call the substring(1,2) method, so we are forced to interrupt the program execution with the generation of our exception type MyException using throw
        throw new MyException("String can not be empty!");
    }
    return s;
}

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

בואו נסתכל על דוגמה מהעולם האמיתי. תארו לעצמכם שיש קטע בכביש מהיר עם גשר חירום עם כושר עומס מוגבל. אם רכב בעל מסה העולה על כושר הנשיאה של הגשר נוסע על פניו, הוא עלול לקרוס, והמצב של הנהג עלול להפוך, בלשון המעטה, לחריג. כדי למנוע את זה, שירות הדרכים מתקין מראש שלטי אזהרה על הכביש. נהג המכונית, מביט בתמרור האזהרה, ישווה את משקל מכוניתו למשקל המותר בנסיעה על הגשר. אם זה חורג מזה, הוא יעשה מעקף. הודות לפעולות שירות הדרכים, ניתנה לנהגי משאיות, ראשית, אפשרות לשנות את מסלולם מראש, שנית, הוזהרו על הסכנה בנתיב הראשי, ולבסוף, הוזהרו על חוסר האפשרות להשתמש הגשר בתנאים מסוימים.
Исключения в Java - 2
היכולת למנוע ולפתור חריגה בתוכנית כך שהיא תוכל להמשיך היא אחת הסיבות לשימוש בחריגים ב-Java. מנגנון החריגה מאפשר לך גם להגן על הקוד שאתה כותב (ממשק תכנות) מפני שימוש לרעה על ידי המשתמש על ידי אימות (בדיקת) נתונים נכנסים. עכשיו בואו נהיה משטרת התנועה לשנייה. ראשית, כדאי להכיר את המקומות שבהם נהגים יכולים להסתבך. שנית, עליך להכין ולהתקין שלטי אזהרה. לבסוף, עליך לספק מסלולי עקיפה במקרה של סכנה במסלול הראשי. ב-Java, מנגנון החריגה פועל בצורה דומה. בשלב פיתוח התוכנית, אנו "מגנים" על קטעי קוד מסוכנים מפני חריגים באמצעות הבלוק try{}, מספקים נתיבי "גיבוי" באמצעות הבלוק catch{}, ובגוש הסופי{} אנו כותבים קוד שמתבצע ב- תוכנית לכל תוצאה. במקרים בהם אין באפשרותנו לספק "מסלול חירום" או בכוונה להשאיר את הבחירה למשתמש, עלינו לפחות להזהיר אותו מפני הסכנה. למה? רק דמיינו את זעמו של נהג שיגיע לגשר חירום שלא ניתן לנהוג בו מבלי להיתקל בתמרור אזהרה אחד בדרך! בתכנות, בעת כתיבת המחלקות והשיטות שלנו, אנחנו לא תמיד יכולים לחזות את ההקשר של השימוש בהם על ידי מפתחים אחרים בתוכנות שלהם, ולכן אנחנו לא יכולים לחזות את הנתיב הנכון ב-100% לפתרון מצב החריג. יחד עם זאת, נוהג טוב להזהיר את המשתמשים מהקוד שלנו על אפשרות של חריגה. מנגנון החריגה של Java מאפשר לנו לעשות זאת על ידי שימוש ב-throws - בעצם הכרזה על ההתנהגות הכללית של השיטה שלנו לזרוק חריגה, ובכך להשאיר את זה למשתמש של השיטה לכתוב קוד לטפל בחריג ב-Java.

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

כאשר אינך מתכנן לטפל בחריג בשיטה שלך, אך רוצה להזהיר את המשתמשים בשיטה לגבי מצבי חריגה אפשריים, השתמש במילת המפתח throws. מילת מפתח זו בחתימת שיטה פירושה שבתנאים מסוימים השיטה עשויה לזרוק חריג. אזהרה זו היא חלק מממשק השיטה ונותנת למשתמש את הזכות להתאים אישית את היישום של מטפל החריגים. לאחר זריקות אנו מציינים את סוג החריגה הנזרקת. אלו הם בדרך כלל צאצאים של מחלקת ה- Java Exception . מכיוון ש-Java היא שפה מונחה עצמים, כל החריגים ב-Java הם אובייקטים.
Исключения в Java - 3

היררכיית חריגים של Java

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

יצירת חריגה

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

טיפול חריג

היצירה של בלוקי קוד שעבורם אנו מספקים טיפול בחריגים ב-Java מתבצעת בתוכנית באמצעות המבנים try{}catch, try{}catch{}finally, try{}finally{}.
Исключения в Java - 4
כאשר מועלה חריג בבלוק ניסיון, מחפשים את מטפל החריג בבלוק ה-catch הבא. אם ה-catch מכיל מטפל לסוג זה של חריגה, השליטה עוברת אליו. אם לא, ה-JVM מחפש מטפל עבור אותו סוג חריג בשרשרת הקריאות למתודה עד שנמצא מלכוד מתאים. לאחר ביצוע בלוק התפיסה, השליטה מועברת לבלוק סופית אופציונלי . אם לא נמצא בלוק תפיסה מתאים, ה-JVM מפסיק את ביצוע התוכנית ומציג ערימה של קריאות מתודה - מעקב מחסנית , לאחר שביצע בעבר את קוד החסימה הסופית, אם קיים. דוגמה לטיפול בחריגים:
public class Print {

     void print(String s) {
        if (s == null) {
            throw new NullPointerException("Exception: s is null!");
        }
        System.out.println("Inside method print: " + 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 was processed. Program continues");
            }
            finally {
                System.out.println("Inside bloсk finally");
            }
            System.out.println("Go program....");
            System.out.println("-----------------");
        }

    }
    }
תוצאות השיטה העיקרית :
Inside method print: first step
Inside bloсk finally
Go program....
-----------------
Exception: s is null!
Exception was processed. Program continues
Inside bloсk finally
Go program....
-----------------
Inside method print: second step
Inside bloсk finally
Go program....
-----------------
הבלוק finallyמשמש בדרך כלל לסגירת זרמים שנפתחו בבלוק הנסי או כדי לפנות משאבים. עם זאת, בעת כתיבת תוכנית, לא תמיד ניתן לעקוב אחר סגירת כל המשאבים. כדי להקל על חיינו, מפתחי Java הציעו לנו מבנה try-with-resourcesשסוגר אוטומטית משאבים שנפתחו בבלוק ניסיון. ניתן לשכתב את הדוגמה הראשונה שלנו כך 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 ("String can not 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("String can not be empty!");
        }
    } catch (IOException | MyException e) {
        System.out.println(e.getMessage());
    }
    return s;
}

תוצאות

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