תבנית Try With Resources
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 62 מתוך 87.
כשעובדים עם משאבים כמו זרמי קבצים או חיבורי מסד נתונים, תמיד צריך לסגור אותם כשמסיימים. אחרת מסתכנים בדליפות זיכרון. הגישה המסורתית משתמשת בבלוק finally, אבל היא מסורבלת ונוטה לשגיאות.
ההצהרה try-with-resources של Java סוגרת משאבים באופן אוטומטי כשהבלוק מסתיים. אפשר להשתמש בכל מחלקה שמממשת את הממשק AutoCloseable עם התחביר הזה:
// הגישה המסורתית - מסורבלת ומסוכנת
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} finally {
if (reader != null) {
reader.close(); // גם כאן עלול להיזרק חריג!
}
}
// Try-with-resources - נקי ובטוח
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
} // נסגר כאן אוטומטיתאפשר לנהל משאבים מרובים על ידי הפרדתם בנקודה-פסיק. הם נסגרים בסדר הפוך לסדר ההכרזה עליהם:
try (FileReader fr = new FileReader("input.txt");
BufferedReader br = new BufferedReader(fr)) {
// השתמש בשני המשאבים
} // br נסגר תחילה, ואז frכדי ליצור מחלקה משלך שניתנת לסגירה אוטומטית, יש לממש את הממשק AutoCloseable ואת המתודה היחידה שלו, close():
public class DatabaseConnection implements AutoCloseable {
public DatabaseConnection() {
System.out.println("Connection opened");
}
@Override
public void close() {
System.out.println("Connection closed");
}
}התבנית הזו מבטיחה שמשאבים ישוחררו תמיד כראוי, גם אם מתרחשות חריגות במהלך העיבוד.
אתגר
קלבואו נבנה מערכת לניהול משאבים שמדגימה את העוצמה של try-with-resources! תיצרו מחלקות מותאמות אישית שניתנות לסגירה אוטומטית, המדמות ניהול של חיבורים ושל הפעלות באתר, ומבטיחות שהם תמיד ייסגרו כראוי.
תארגנו את הקוד בשלושה קבצים:
Connection.java: צרו מחלקה שמדמה חיבור למסד נתונים. המחלקהConnectionצריכה לממש אתAutoCloseable. עליה לכלול שדה פרטי עבור שם החיבור (String), בנאי שמקבל את השם ומדפיס[name] connection opened, שיטהquery(String sql)שמדפיסהExecuting on [name]: [sql], ואת השיטה הנדרשתclose()שמדפיסה[name] connection closed.Session.java: צרו מחלקה נוספת שניתנת לסגירה אוטומטית ומדמה הפעלה של משתמש. גם המחלקהSessionצריכה לממש אתAutoCloseable. הוסיפו שדה פרטי עבור שם המשתמש (String), בנאי שמקבל את שם המשתמש ומדפיסSession started for [username], שיטהperformAction(String action)שמדפיסה[username] performed: [action], ושיטהclose()שמדפיסהSession ended for [username].Main.java: חברו את מערכת ניהול המשאבים שלכם! תקבלו שלוש קלטים: שם חיבור, שם משתמש ופעולה לביצוע.ראשית, הדגימו ניהול של משאב יחיד. הדפיסו
=== Single Resource ===, ולאחר מכן השתמשו ב-try-with-resources כדי ליצורConnectionעם השם הנתון. בתוך בלוק ה-try, קראו ל-query("SELECT * FROM users"). החיבור אמור להיסגר אוטומטית בסיום הבלוק.לאחר מכן, הדגימו ניהול של כמה משאבים. הדפיסו שורה ריקה, ולאחר מכן
=== Multiple Resources ===. השתמשו ב-try-with-resources עםConnection(באמצעות אותו שם) ועםSession(באמצעות שם המשתמש), והצהירו עליהם לפי הסדר הזה, עם נקודה-פסיק ביניהם. בתוך בלוק ה-try, קראו תחילה ל-query("INSERT INTO logs")בחיבור, ולאחר מכן קראו ל-performActionעם פעולת הקלט בהפעלה. שימו לב לסדר הסגירה ההפוך של המשאבים!
תקבלו שלוש קלטים לפי הסדר: שם חיבור (String), שם משתמש (String) ופעולה (String).
שימו לב כיצד try-with-resources מייתר קריאות מפורשות ל-close ובלוקי finally. מובטח שהמשאבים ייסגרו גם אם יתרחשו חריגות, וכמה משאבים ייסגרו בסדר הפוך לסדר ההצהרה שלהם!
נסו בעצמכם
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String connectionName = scanner.nextLine();
String username = scanner.nextLine();
String action = scanner.nextLine();
// === Single Resource ===
// TODO: הדפס את הכותרת
// TODO: השתמש ב-try-with-resources כדי ליצור Connection
// TODO: בתוך בלוק ה-try, קרא ל-query("SELECT * FROM users")
// === Multiple Resources ===
// TODO: הדפס שורה ריקה ואת הכותרת
// TODO: השתמש ב-try-with-resources עם Connection ו-Session
// TODO: בתוך בלוק ה-try:
// - קרא ל-query("INSERT INTO logs") על החיבור
// - קרא ל-performAction עם הפעולה שהתקבלה כקלט על ה-session
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותשדות (מאפיינים)מתודת הבנאיהעמסת בנאיםחזרה – מחשבון פשוט4ירושה
ירושה בסיסית (extends)מילת המפתח superדריסת מתודות (@Override)שרשור בנאיםהמחלקה Objectירושה יחידה ורב־רמתיתלמה אין ירושה מרובה של מחלקותסיכום – היררכיית עובדים7מתודות מיוחדות ומחלקת Object
מתודת toString()equals() ו-hashCode()מתודת clone()compareTo() ו-Comparableהממשק Comparatorסיכום – מיון מותאם אישית10טיפול בחריגות ב-OOP
היררכיית מחלקות החריגותחריגות מותאמות אישיתשגיאות Checked לעומת Uncheckedתבנית Try With Resourcesחזרה – משתמש מאומת2מצייני גישה ואנקפסולציה
סקירה של רמות הגישהמתודות Getter ו-Setterהסתרת מידעמילת המפתח finalסיכום – מנהל חשבון בנק5פולימורפיזם
יסודות העמסת מתודותדריסת מתודות (בזמן ריצה)המרה כלפי מעלה וכלפי מטההאופרטור instanceofמחלקות ומתודות מופשטותסיכום – מחשבון צורות8מושגי OOP מתקדמים
הרכבה מול ירושהאגרגציה מול הרכבהמחלקות פנימיות, מקוננות ואנונימיותEnums ומתודות של EnumRecords (Java 16+)מחלקות חתומות (Java 17+)3מאפייני מחלקה וחברים סטטיים
משתני מופע לעומת משתנים סטטייםמתודות סטטיותבלוקים סטטייםקבועים (static final)סיכום — מונה ומחלקת עזר6ממשקים ומחלקות מופשטות
מבוא לממשקיםמימוש ממשקיםמימוש של כמה ממשקיםמתודות ברירת מחדל וסטטיות בממשקמחלקות מופשטות לעומת ממשקיםממשקים פונקציונלייםסיכום – מערכת תשלומיםתרגלו בעצמכם: קומפיילר Java אונליין