טיפול בחריגים בג'אווה

1. סקירה כללית

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

2. עקרונות ראשונים

2.1. מה זה?

כדי להבין טוב יותר חריגים וטיפול בחריגים, בואו לערוך השוואה בין החיים האמיתיים.

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

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

2.2. למה להשתמש בזה?

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

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

עלינו להתמודד עם תנאים אלה מכיוון שהם משפיעים על זרימת היישום בצורה שלילית וצורה חריגים:

רשימה סטטית ציבורית getPlayers () זורק IOException {Path path = Paths.get ("players.dat"); רשימת נגנים = Files.readAllLines (נתיב); return players.stream () .map (Player :: new) .collect (Collectors.toList ()); }

קוד זה בוחר שלא לטפל ב- IOException, מעביר אותו במקום זאת על ערימת השיחות. בסביבה אידיאלית, הקוד עובד בסדר.

אבל מה עלול לקרות בייצור אם players.dat חסר?

חריג בשרשור "ראשי" java.nio.file.NoSuchFileException: players.dat <- קובץ players.dat אינו קיים ב- sun.nio.fs.WindowsException.translateToIOException (מקור לא ידוע) ב- sun.nio.fs.WindowsException .rethrowAsIOException (מקור לא ידוע) // ... עוד ערימת מעקב ב- java.nio.file.Files.readAllLines (מקור לא ידוע) ב- java.nio.file.Files.readAllLines (מקור לא ידוע) ב- Exceptions.getPlayers (Exceptions.java : 12) <- יוצא מהכלל בשיטת getPlayers (), בשורה 12 ב- Exceptions.main (Exceptions.java:19) <- getPlayers () נקרא על ידי main (), בשורה 19

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

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

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

בסופו של דבר, חריגים הם רק אובייקטים של Java, כאשר כולם משתרעים על זורק:

 ---> שגיאת חריג זורקת | (מסומן) (לא מסומן) | RuntimeException (לא מסומן)

ישנן שלוש קטגוריות עיקריות של תנאים חריגים:

  • חריגים נבדקו
  • חריגים לא מסומנים / חריגי זמן ריצה
  • טעויות

זמן ריצה וחריגים לא מסומנים מתייחסים לאותו הדבר. לעתים קרובות אנו יכולים להשתמש בהם לסירוגין.

3.1. חריגים מסומנים

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

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

כמה דוגמאות לחריגים בדוקים הם IOException ו ServletException.

3.2. חריגים לא מסומנים

חריגים לא מסומנים הם יוצאים מהכלל שעושה מהדר Java לֹא לדרוש מאיתנו לטפל.

במילים פשוטות, אם אנו יוצרים חריג שמתרחב חריגת זמן ריצה, זה לא ייבדק; אחרת, זה ייבדק.

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

כמה דוגמאות לחריגים לא מסומנים הן NullPointerException, אי-חוקי ארגומנט, ו ExceptionException.

3.3. טעויות

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

ולמרות שהם לא מאריכים חריגת זמן ריצה, הם גם לא מסומנים.

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

כמה דוגמאות לשגיאות הן א StackOverflowError ו OutOfMemoryError.

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

ב- API של Java, יש הרבה מקומות שבהם הדברים יכולים להשתבש, וחלק מהמקומות האלה מסומנים בחריגים, בחתימה או ב- Javadoc:

/ ** * @exception FileNotFoundException ... * / public Scanner (String fileName) זורק FileNotFoundException {// ...}

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

4.1. זורק

הדרך הפשוטה ביותר "להתמודד" עם חריג היא לזרוק אותו מחדש:

public int getPlayerScore (String playerFile) זורק FileNotFoundException {תוכן הסורק = סורק חדש (קובץ חדש (playerFile)); החזר Integer.parseInt (contents.nextLine ()); }

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

מזויף יכול לזרוק א NumberFormatException, אך מכיוון שהוא אינו מסומן, איננו נדרשים לטפל בו.

4.2. נסה לתפוס

אם אנחנו רוצים לנסות להתמודד עם החריג בעצמנו, אנחנו יכולים להשתמש ב- נסה לתפוס לַחסוֹם. אנחנו יכולים להתמודד עם זה על ידי ביטול מחדש של החריג שלנו:

public int getPlayerScore (מנגן playerFile) {נסה {תוכן סורק = סורק חדש (קובץ חדש (playerFile)); החזר Integer.parseInt (contents.nextLine ()); } לתפוס (FileNotFoundException noFile) {לזרוק IllegalArgumentException חדש ("הקובץ לא נמצא"); }}

או על ידי ביצוע שלבי התאוששות:

public int getPlayerScore (מנגן playerFile) {נסה {תוכן סורק = סורק חדש (קובץ חדש (playerFile)); החזר Integer.parseInt (contents.nextLine ()); } לתפוס (FileNotFoundException noFile) {logger.warn ("הקובץ לא נמצא, מאפס את הציון."); החזר 0; }}

4.3. סוף כל סוף

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

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

בהחלט, בין אם נוכל לקרוא את הקובץ ובין אם לאו, אנו רוצים לוודא שנעשה את הניקוי המתאים!

בואו ננסה זאת בדרך ה"עצלנית ":

public int getPlayerScore (String playerFile) זורק FileNotFoundException {תוכן הסורק = null; נסה {content = סורק חדש (קובץ חדש (playerFile)); החזר Integer.parseInt (contents.nextLine ()); } סוף סוף {if (contents! = null) {contents.close (); }}} 

הנה ה סוף כל סוף בלוק מציין איזה קוד אנו רוצים שג'אווה תפעל ללא קשר למה שקורה בניסיון לקרוא את הקובץ.

גם אם א FileNotFoundException נזרק על ערימת השיחות, ג'אווה תתקשר לתוכן של סוף כל סוף לפני שעושים את זה.

שנינו יכולים להתמודד עם החריג ו ודא שהמשאבים שלנו ייסגרו:

public int getPlayerScore (String playerFile) {תוכן הסורק; נסה {content = סורק חדש (קובץ חדש (playerFile)); החזר Integer.parseInt (contents.nextLine ()); } לתפוס (FileNotFoundException noFile) {logger.warn ("הקובץ לא נמצא, מאפס את הציון."); החזר 0; } סוף סוף {נסה {if (contents! = null) {contents.close (); }} לתפוס (IOException io) {logger.error ("לא ניתן היה לסגור את הקורא!", io); }}}

כי סגור היא גם שיטה "מסוכנת", אנחנו גם צריכים לתפוס את החריג שלה!

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

4.4. לְנַסוֹת-עם משאבים

למרבה המזל, נכון ל- Java 7, אנו יכולים לפשט את התחביר הנ"ל כאשר אנו עובדים עם דברים המשתרעים ניתן לסגירה אוטומטית:

public int getPlayerScore (מנגן playerFile) {נסה (תוכן סורק = סורק חדש (קובץ חדש (playerFile))) {החזר Integer.parseInt (contents.nextLine ()); } לתפוס (FileNotFoundException e) {logger.warn ("הקובץ לא נמצא, איפוס הציון."); החזר 0; }}

כאשר אנו מציבים אזכורים שהם ניתן לסגירה אוטומטית בתוך ה לְנַסוֹת הצהרה, אז אנחנו לא צריכים לסגור את המשאב בעצמנו.

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

עיין במאמר שלנו המוקדש ל לְנַסוֹת-עם משאבים למידע נוסף.

4.5. מרובות לתפוס בלוקים

לפעמים, הקוד יכול לזרוק יותר מחריג אחד, ואנחנו יכולים לקבל יותר מאחד לתפוס ידית בלוק כל אחת בנפרד:

public int getPlayerScore (String playerFile) {try (תוכן הסורק = סורק חדש (קובץ חדש (playerFile))) {return Integer.parseInt (contents.nextLine ()); } לתפוס (IOException e) {logger.warn ("קובץ הנגן לא היה נטען!", e); החזר 0; } לתפוס (NumberFormatException e) {logger.warn ("קובץ הנגן פגום!", e); החזר 0; }}

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

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

בואו נגיד שאנחנו צריכים לטפל FileNotFoundException באופן שונה מהכללי יותר IOException:

public int getPlayerScore (מנגן playerFile) {נסה (תוכן סורק = סורק חדש (קובץ חדש (playerFile))) {החזר Integer.parseInt (contents.nextLine ()); } לתפוס (FileNotFoundException e) {logger.warn ("קובץ הנגן לא נמצא!", e); החזר 0; } לתפוס (IOException e) {logger.warn ("קובץ הנגן לא היה נטען!", e); החזר 0; } לתפוס (NumberFormatException e) {logger.warn ("קובץ הנגן פגום!", e); החזר 0; }}

Java מאפשרת לנו להתמודד עם חריגים של מחלקות משנה בנפרד זכור למקם אותם גבוה יותר ברשימת התפיסות.

4.6. הִתאַחֲדוּת לתפוס בלוקים

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

public int getPlayerScore (מנגן playerFile) {נסה (תוכן סורק = סורק חדש (קובץ חדש (playerFile))) {החזר Integer.parseInt (contents.nextLine ()); } לתפוס (IOException | NumberFormatException e) {logger.warn ("נכשל טעינת הציון!", e); החזר 0; }}

5. חריגים לזרוק

אם אנחנו לא רוצים להתמודד עם החריג בעצמנו או שאנחנו רוצים לייצר את החריגים שלנו לאחרים להתמודד, אז אנחנו צריכים להכיר את לזרוק מילת מפתח.

נניח שיש לנו את החריג המסומן הבא שיצרנו בעצמנו:

מחלקה ציבורית TimeoutException מרחיב חריג {timeoutException ציבורי (הודעת מחרוזת) {סופר (הודעה); }}

ויש לנו שיטה שעלולה להימשך זמן רב להשלמתה:

רשימת ציבורי loadAllPlayers (String playersFile) {// ... פעולה ארוכה}

5.1. לזרוק חריג בדוק

כמו לחזור משיטה, אנחנו יכולים לזרוק בכל נקודה.

כמובן שעלינו לזרוק כשמנסים לציין שמשהו השתבש:

public list loadAllPlayers (String playersFile) זורק TimeoutException {while (! tooLong) {// ... פעולה ארוכה פוטנציאלית} זורק TimeoutException חדש ("פעולה זו ארכה זמן רב מדי"); }

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

5.2. לזרוקחריג לא מסומן

אם אנחנו רוצים לעשות משהו כמו, למשל, לאמת קלט, נוכל להשתמש במקום זאת בחריג לא מסומן:

public load loadAllPlayers (String playersFile) זורק TimeoutException {if (! isFilenameValid (playersFile)) {throw new IllegalArgumentException ("שם הקובץ אינו תקף!"); } // ...} 

כי IllegalArgumentException אינו מסומן, איננו צריכים לסמן את השיטה, למרות שאנו מוזמנים.

יש שמסמנים את השיטה בכל מקרה כסוג של תיעוד.

5.3. עטיפה והטלה מחדש

אנחנו יכולים גם לבחור לזרוק מחדש חריג שתפסנו:

public list loadAllPlayers (String playersFile) זורק IOException {try {// ...} לתפוס (IOException io) {throw io; }}

או בצע לעטוף ולסדר מחדש:

רשימת הציבורים loadAllPlayers (String playersFile) זורק PlayerLoadException {נסה {// ...} לתפוס (IOException io) {לזרוק PlayerLoadException חדש (io); }}

זה יכול להיות נחמד לאיחוד חריגים רבים ושונים לאחד.

5.4. לזרוק מחדש זורק אוֹ יוצא מן הכלל

עכשיו למקרה מיוחד.

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

public list loadAllPlayers (String playersFile) {try {throw new NullPointerException (); } לתפוס (Throwable t) {לזרוק t; }}

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

זה שימושי עם שיעורי פרוקסי ושיטות. עוד על כך ניתן למצוא כאן.

5.5. יְרוּשָׁה

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

בנסיבות שבה השיטה שלנו מציגה חריג מסומן:

מחלקה ציבורית חריגים {public list loadAllPlayers (String playersFile) זורק TimeoutException {// ...}}

תת-מחלקה יכולה להיות עם חתימה "פחות מסוכנת":

מחלקה ציבורית FewerExceptions מרחיב חריגים {@Override public list loadAllPlayers (String playersFile) {// overridden}}

אבל לא "יותר חתימה מסוכנת יותר:

מחלקה ציבורית MoreExceptions מרחיב חריגים {@Override public list loadAllPlayers (String playersFile) זורק את MyCheckedException {// נדרס}}

הסיבה לכך היא כי החוזים נקבעים בזמן הקומפילציה לפי סוג הייחוס. אם אני יוצר מופע של MoreExceptions ולשמור אותו ל חריגים:

חריגים חריגים = MoreExceptions חדשים (); exceptions.loadAllPlayers ("קובץ");

ואז ה- JVM רק יגיד לי לתפוס ה פסק זמן פסק זמן, וזה לא בסדר מאז שאמרתי את זה MoreExceptions # loadAllPlayers זורק חריג אחר.

במילים פשוטות, מחלקות משנה יכולות לזרוק פחות חריגים בדוקים מאשר מעמד העל שלהם, אבל לא יותר.

6. אנטי דפוסים

6.1. בליעה חריגים

עכשיו, יש דרך אחת אחרת שיכולנו לספק את המהדר:

public int getPlayerScore (String playerFile) {נסה {// ...} לתפוס (חריג e) {} // <== לתפוס ולבלוע להחזיר 0; }

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

ישנם מקרים בהם יש חריג מסומן שאנו בטוחים כי לעולם לא יקרה. במקרים אלה, עלינו להוסיף לפחות הערה לפיה אכלנו בכוונה את החריג:

public int getPlayerScore (String playerFile) {נסה {// ...} לתפוס (IOException e) {// זה לעולם לא יקרה}}

דרך נוספת בה אנו יכולים "לבלוע" חריג היא להדפיס את החריג לזרם השגיאה בפשטות:

public int getPlayerScore (String playerFile) {try {// ...} catch (Exception e) {e.printStackTrace (); } להחזיר 0; }

שיפרנו מעט את מצבנו על ידי לפחות כתיבת השגיאה איפשהו לאבחון מאוחר יותר.

עדיף, אם כן, שנשתמש בלוגר:

public int getPlayerScore (String playerFile) {try {// ...} catch (IOException e) {logger.error ("לא ניתן היה לטעון את הציון", e); החזר 0; }}

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

לבסוף, אנו יכולים לבלוע חריג בשוגג על ידי שלא לכלול אותו כגורם כאשר אנו משליכים חריג חדש:

public int getPlayerScore (String playerFile) {try {// ...} catch (IOException e) {throw new PlayerScoreException (); }} 

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

עדיף לנו לעשות:

public int getPlayerScore (String playerFile) {try {// ...} לתפוס (IOException e) {לזרוק PlayerScoreException חדש (e); }}

שימו לב להבדל העדין של הכללה IOException כמו גורם שֶׁל PlayerScoreException.

6.2. באמצעות לַחֲזוֹר ב סוף כל סוף לַחסוֹם

דרך נוספת לבלוע חריגים היא לַחֲזוֹר מ ה סוף כל סוף לַחסוֹם. זה רע מכיוון שעל ידי חזרה פתאומית, ה- JVM יפיל את החריג, גם אם הוא נזרק מהקוד שלנו:

public int getPlayerScore (String playerFile) {int score = 0; נסה {לזרוק IOException חדש (); } סוף סוף {ציון חוזר; // <== ה- IOException הושמט}}

על פי מפרט שפת Java:

אם ביצוע חסימת הניסיון יושלם בפתאומיות מכל סיבה אחרת רואז החסימה לבסוף מתבצעת ואז יש ברירה.

אם ה סוף כל סוף החסימה הושלמה כרגיל, ואז הצהרת הניסיון הושלמה בפתאומיות מסיבה R.

אם ה סוף כל סוף חסימה מסתיימת בפתאומיות מסיבה S, ואז הצהרת הניסיון מושלמת בפתאומיות מסיבה S (והסיבה R מושמלת).

6.3. באמצעות לזרוק ב סוף כל סוף לַחסוֹם

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

זה "ימחק" את החריג המקורי מה- לְנַסוֹת לחסום, ואנחנו מאבדים את כל המידע החשוב הזה:

public int getPlayerScore (String playerFile) {try {// ...} catch (IOException io) {throw new IllegalStateException (io); // <== נאכל על ידי סוף סוף} סוף סוף {זרוק OtherException חדש (); }}

6.4. באמצעות לזרוק כ לך ל

יש אנשים שנכנעו גם לפיתוי השימוש לזרוק כ לך ל הַצהָרָה:

חלל ציבורי doSomething () {נסה {// חבורה של קוד לזרוק MyException חדש (); // חבורה קוד שני} תפוס (MyException e) {// חבורה קוד שלישי}}

זה מוזר מכיוון שהקוד מנסה להשתמש בחריגים לבקרת זרימה בניגוד לטיפול בשגיאות.

7. חריגים ושגיאות נפוצים

להלן מספר חריגים ושגיאות נפוצים שכולנו נתקלים בהם מעת לעת:

7.1. חריגים מסומנים

  • IOException - חריג זה הוא בדרך כלל דרך לומר שמשהו ברשת, במערכת הקבצים או במסד הנתונים נכשל.

7.2. RuntimeExceptions

  • אינדקס מערך מחוץ לתחום Exception - חריג זה פירושו שניסינו לגשת לאינדקס מערך שלא קיים, כמו בניסיון להשיג אינדקס 5 ממערך באורך 3.
  • ClassCastException - חריג זה פירושו שניסינו לבצע צוות שחקנים לא חוקי, כמו ניסיון להמיר חוּט לתוך רשימה. בדרך כלל אנו יכולים להימנע מכך על ידי ביצוע הגנתי מופע של בדיקות לפני הליהוק.
  • IllegalArgumentException - חריג זה הוא דרך כללית עבורנו לומר שאחד מהפרמטרים או השיטות המסופקים אינו חוקי.
  • IllegalStateException - חריג זה הוא דרך כללית עבורנו לומר שמצבנו הפנימי, כמו מצב החפץ שלנו, אינו תקף.
  • NullPointerException - חריג זה אומר שניסינו להפנות א ריק לְהִתְנַגֵד. בדרך כלל אנו יכולים להימנע מכך על ידי ביצוע הגנה ריק המחאות או באמצעות אופציונאלי.
  • NumberFormatException - חריג זה אומר שניסינו להמיר א חוּט למספר, אך המחרוזת הכילה תווים לא חוקיים, כמו ניסיון להמיר את "5f3" למספר.

7.3. טעויות

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

8. מסקנה

במאמר זה עברנו את יסודות הטיפול בחריגים וכן כמה דוגמאות לתרגול טוב וגרוע.

כמו תמיד, כל הקוד שנמצא במאמר זה ניתן למצוא באתר GitHub!