מדריך ל- Java סוף סוף מילת מפתח

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

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

נדון גם בכמה מלכודות נפוצות בהן א סוף כל סוף לחסימה יכולה להיות תוצאה בלתי צפויה.

2. מה זה סוף כל סוף?

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

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

2.1. דוגמה מהירה

בוא נסתכל על סוף כל סוף ב נסה לתפוס סוף סוף לַחסוֹם:

נסה את {System.out.println ("הספירה היא" + Integer.parseInt (ספירה)); } לתפוס (NumberFormatException e) {System.out.println ("אין ספירה"); } סוף סוף {System.out.println ("סוף סוף"); } 

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

2.2. באמצעות סוף כל סוף בלי לתפוס לַחסוֹם

כמו כן, אנו יכולים להשתמש א סוף כל סוף חסום עם לְנַסוֹת חסום ללא קשר לשאלה האם לתפוס חסום קיים:

נסה את {System.out.println ("ניסיון פנימי"); } סוף סוף {System.out.println ("בפנים סוף סוף"); }

ונקבל את התפוקה:

בפנים נסה בפנים סוף סוף

2.3. למה סוף כל סוף הוא שימושי

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

הערה: נסה משאבים יכול לשמש גם לסגירת משאבים במקום a סוף כל סוף לַחסוֹם.

3. מתי סוף כל סוף מוצא להורג

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

3.1. לא יוצא שום יוצא מן הכלל

כאשר לְנַסוֹת החסימה משלימה, את סוף כל סוף החסימה מבוצעת, גם אם לא היה חריג:

נסה את {System.out.println ("ניסיון פנימי"); } סוף סוף {System.out.println ("סוף סוף בפנים"); }

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

תפוקות אלה:

בפנים נסה בפנים סוף סוף

3.2. יוצאים מן הכלל ואינם מטופלים

אם יש יוצא מן הכלל והוא לא נתפס, סוף כל סוף החסימה עדיין מבוצעת:

נסה את {System.out.println ("ניסיון פנימי"); לזרוק חריג חדש (); } סוף סוף {System.out.println ("בפנים סוף סוף"); }

ה- JVM מבצע את ה- סוף כל סוף חסום גם במקרה של חריג שלא טופל.

והתפוקה תהיה:

פנימה נסה פנימה סוף סוף חריג בשרשור "הראשי" java.lang.Exception

3.3. יוצאים מהכלל ומטופלים

אם יש יוצא מן הכלל והוא נתפס על ידי לתפוס לחסום, את סוף כל סוף החסימה עדיין מבוצעת:

נסה את {System.out.println ("ניסיון פנימי"); לזרוק חריג חדש (); } לתפוס (חריג e) {System.out.println ("תפיסה פנימית"); } סוף סוף {System.out.println ("סוף סוף בפנים"); }

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

בפנים נסה בפנים לתפוס בפנים סוף סוף

3.4. שיטה חוזרת מ לְנַסוֹת לַחסוֹם

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

נסה את {System.out.println ("ניסיון פנימי"); חזור "מנסיון"; } סוף סוף {System.out.println ("בפנים סוף סוף"); }

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

נקבל את התפוקה:

בפנים נסה בפנים סוף סוף

3.5. שיטה חוזרת מ לתפוס לַחסוֹם

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

נסה את {System.out.println ("ניסיון פנימי"); לזרוק חריג חדש (); } לתפוס (חריג e) {System.out.println ("תפיסה פנימית"); להחזיר "מהתפס"; } סוף סוף {System.out.println ("סוף סוף בפנים"); }

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

בפנים נסה בפנים לתפוס בפנים סוף סוף

4. מתי סוף כל סוף לא מוצא להורג

למרות שאנחנו תמיד מצפים מ- JVM לבצע את ההצהרות בתוך a סוף כל סוף לחסום, ישנם מצבים בהם ה- JVM לא יבצע א סוף כל סוף לַחסוֹם.

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

4.1. קורא System.exit

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

נסה את {System.out.println ("ניסיון פנימי"); System.exit (1); } סוף סוף {System.out.println ("סוף סוף בפנים"); }

תפוקות אלה:

נסה בפנים

4.2. קורא לַעֲצוֹר

דומה ל System.exit, קריאה ל זמן ריצה גם עוצר את ההוצאה לפועל ו- JVM לא מבצע שום סוף כל סוף חסימות:

נסה את {System.out.println ("ניסיון פנימי"); Runtime.getRuntime (). עצור (1); } סוף סוף {System.out.println ("סוף סוף בפנים"); }

לפיכך, התפוקה תהיה:

נסה בפנים

4.3. חוט הדמון

אם חוט Daemon נכנס לביצוע של a נסה / סוף סוף לחסום וכל שאר השרשורים שאינם שדים יוצאים לפני שרשור השדים מבצע את ה- סוף כל סוף לחסום, ה- JVM לא ממתין לשרשור הדאמון שיסיים את הביצוע של סוף כל סוף לַחסוֹם:

Runnable runnable = () -> {נסה {System.out.println ("בתוך ניסיון"); } סוף סוף {נסה {Thread.sleep (1000); System.out.println ("סוף סוף בפנים"); } לתפוס (InterruptedException e) {e.printStackTrace (); }}}; חוט רגיל = חוט חדש (ניתן להריצה); חוט הדמון = חוט חדש (ניתן להריצה); daemon.setDaemon (נכון); regular.start (); Thread.sleep (300); daemon.start ();

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

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

הנה הפלט:

בפנים נסה בפנים נסה בפנים סוף סוף

4.4. JVM מגיע לולאה אינסופית

הנה לְנַסוֹת חסום המכיל אינסוף בזמן לוּלָאָה:

נסה את {System.out.println ("ניסיון פנימי"); בעוד (נכון) {}} סוף סוף {System.out.println ("סוף סוף בפנים"); }

למרות שזה לא ספציפי ל סוף כל סוףראוי להזכיר שאם ה לְנַסוֹת אוֹ לתפוס בלוק מכיל לולאה אינסופית, ה- JVM לעולם לא יגיע לאף בלוק מעבר לאותה לולאה.

5. מלכודות נפוצות

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

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

5.1. התעלמות מחריג

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

נסה את {System.out.println ("ניסיון פנימי"); לזרוק RuntimeException חדש (); } סוף סוף {System.out.println ("סוף סוף בפנים"); לחזור "מ סוף סוף"; }

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

5.2. מתעלם מאחר לַחֲזוֹר הצהרות

א לַחֲזוֹר הצהרה ב סוף כל סוף הבלוק מתעלם מכל הצהרת החזרה אחרת ב- לְנַסוֹת אוֹ לתפוס לַחסוֹם. רק ה לַחֲזוֹר הצהרה ב סוף כל סוף חסימת ביצוע:

נסה את {System.out.println ("ניסיון פנימי"); חזור "מנסיון"; } סוף סוף {System.out.println ("סוף סוף בפנים"); לחזור "מ סוף סוף"; }

בדוגמה זו השיטה תמיד חוזרת "מסוף סוף" ומתעלם לחלוטין מה- לַחֲזוֹר הצהרה ב לְנַסוֹת לַחסוֹם. זה יכול להיות באג קשה מאוד לאיתור ולכן עלינו להימנע משימוש לַחֲזוֹר ב סוף כל סוף חסימות.

5.3. משנה מה מושלך או מוחזר

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

נסה את {System.out.println ("ניסיון פנימי"); חזור "מנסיון"; } סוף סוף {זרוק RuntimeException (); }

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

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

6. מסקנה

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

לבסוף, בדקנו כמה מלכודות נפוצות הקשורות לשימוש סוף כל סוף חסימות.

כמו תמיד, קוד המקור המשמש במדריך זה זמין ב- GitHub.