1. बाहरी संसाधन
जैसे ही जावा प्रोग्राम चलता है, कभी-कभी यह जावा मशीन के बाहर की संस्थाओं के साथ इंटरैक्ट करता है। उदाहरण के लिए, डिस्क पर फ़ाइलों के साथ। इन संस्थाओं को आमतौर पर बाहरी संसाधन कहा जाता है। आंतरिक संसाधन जावा मशीन के अंदर बनाए गए ऑब्जेक्ट हैं।
आमतौर पर, बातचीत इस योजना का अनुसरण करती है:
ट्रैकिंग संसाधन
ऑपरेटिंग सिस्टम उपलब्ध संसाधनों पर सख्ती से नज़र रखता है, और विभिन्न कार्यक्रमों से उन तक साझा पहुँच को भी नियंत्रित करता है। उदाहरण के लिए, यदि एक प्रोग्राम किसी फ़ाइल को बदलता है, तो दूसरा प्रोग्राम उस फ़ाइल को बदल (या हटा) नहीं सकता है। यह सिद्धांत फाइलों तक ही सीमित नहीं है, लेकिन वे सबसे आसानी से समझने योग्य उदाहरण प्रदान करते हैं।
ऑपरेटिंग सिस्टम में ऐसे कार्य (एपीआई) होते हैं जो किसी प्रोग्राम को संसाधनों को प्राप्त करने और/या जारी करने की अनुमति देते हैं। यदि कोई संसाधन व्यस्त है, तो केवल वह प्रोग्राम जिसने इसे अधिग्रहित किया है, इसके साथ काम कर सकता है। यदि कोई संसाधन निःशुल्क है, तो कोई भी प्रोग्राम उसे प्राप्त कर सकता है।
कल्पना कीजिए कि आपके कार्यालय ने कॉफी मग साझा किए हैं। यदि कोई मग लेता है, तो अन्य लोग अब इसे नहीं ले सकते। लेकिन मग को एक बार इस्तेमाल करने, धोकर वापस अपनी जगह पर रख देने के बाद, कोई भी इसे दोबारा ले सकता है। बस या मेट्रो में सीटों की स्थिति समान है। अगर सीट खाली है तो कोई भी ले सकता है। यदि किसी आसन पर कब्जा कर लिया जाता है, तो इसे लेने वाले द्वारा नियंत्रित किया जाता है।
बाह्य संसाधनों की प्राप्ति ।
हर बार जब आपका जावा प्रोग्राम डिस्क पर फ़ाइल के साथ काम करना शुरू करता है, तो जावा मशीन ऑपरेटिंग सिस्टम से इसके लिए विशेष एक्सेस मांगती है। यदि संसाधन मुक्त है, तो जावा मशीन इसे प्राप्त कर लेती है।
लेकिन आपके द्वारा फ़ाइल के साथ काम करना समाप्त करने के बाद, यह संसाधन (फ़ाइल) जारी किया जाना चाहिए, अर्थात आपको ऑपरेटिंग सिस्टम को सूचित करने की आवश्यकता है कि अब आपको इसकी आवश्यकता नहीं है। यदि आप ऐसा नहीं करते हैं, तो संसाधन आपके प्रोग्राम के पास बना रहेगा।
ऑपरेटिंग सिस्टम प्रत्येक चल रहे प्रोग्राम के कब्जे वाले संसाधनों की एक सूची रखता है। यदि आपका प्रोग्राम निर्दिष्ट संसाधन सीमा से अधिक है, तो ऑपरेटिंग सिस्टम अब आपको नए संसाधन नहीं देगा।
अच्छी खबर यह है कि यदि आपका प्रोग्राम समाप्त हो जाता है, तो सभी संसाधन स्वचालित रूप से जारी हो जाते हैं (ऑपरेटिंग सिस्टम स्वयं ऐसा करता है)।
बुरी खबर यह है कि यदि आप एक सर्वर एप्लिकेशन लिख रहे हैं (और जावा में बहुत सारे सर्वर एप्लिकेशन लिखे गए हैं), तो आपके सर्वर को बिना रुके दिनों, हफ्तों और महीनों तक चलने में सक्षम होना चाहिए। और अगर आप एक दिन में 100 फाइलें खोलते हैं और उन्हें बंद नहीं करते हैं, तो कुछ हफ़्ते में आपका आवेदन अपनी संसाधन सीमा तक पहुँच जाएगा और क्रैश हो जाएगा। यह स्थिर कार्य के महीनों से बहुत कम हो रहा है।
2. close()
विधि
बाहरी संसाधनों का उपयोग करने वाली कक्षाओं के पास उन्हें जारी करने का एक विशेष तरीका है: close()
.
नीचे हम एक ऐसे प्रोग्राम का उदाहरण देते हैं जो एक फ़ाइल में कुछ लिखता है और जब यह पूरा हो जाता है तो फ़ाइल को बंद कर देता है, अर्थात यह ऑपरेटिंग सिस्टम के संसाधनों को मुक्त करता है। ऐसा कुछ दिखता है:
कोड | टिप्पणी |
---|---|
|
फ़ाइल का पथ। फ़ाइल ऑब्जेक्ट प्राप्त करें: संसाधन प्राप्त करें। फ़ाइल में लिखें फ़ाइल बंद करें - संसाधन जारी करें |
फ़ाइल (या अन्य बाहरी संसाधनों) के साथ काम करने के बाद, आपको close()
बाहरी संसाधन से जुड़े ऑब्जेक्ट पर विधि को कॉल करना होगा।
अपवाद
यह सब साधारण लगता है। लेकिन प्रोग्राम के चलते अपवाद हो सकते हैं, और बाहरी संसाधन जारी नहीं किए जाएंगे। और यह बहुत बुरा है।
यह सुनिश्चित करने के लिए कि close()
विधि हमेशा कॉल की जाती है, हमें अपने कोड को try
- ब्लॉक में लपेटने और ब्लॉक में विधि जोड़ने की आवश्यकता होती है catch
। यह कुछ ऐसा दिखाई देगा:finally
close()
finally
try
{
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
यह कोड संकलित नहीं होगा, क्योंकि output
चर ब्लॉक के अंदर घोषित किया गया है try {}
, और इसलिए finally
ब्लॉक में दिखाई नहीं दे रहा है।
आइए इसे ठीक करें:
FileOutputStream output = new FileOutputStream(path);
try
{
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
यह ठीक है, लेकिन अगर हम वस्तु बनाते समय कोई त्रुटि होती है तो यह काम नहीं करेगा FileOutputStream
, और यह काफी आसानी से हो सकता है।
आइए इसे ठीक करें:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
अभी भी कुछ आलोचनाएँ हैं। सबसे पहले, यदि FileOutputStream
ऑब्जेक्ट बनाते समय कोई त्रुटि होती है, तो output
चर शून्य होगा। इस संभावना का हिसाब finally
ब्लॉक में होना चाहिए।
दूसरा, close()
विधि को हमेशा finally
ब्लॉक में कहा जाता है, जिसका अर्थ है कि यह try
ब्लॉक में आवश्यक नहीं है। अंतिम कोड इस तरह दिखेगा:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (output != null)
output.close();
}
यहां तक कि अगर हम ब्लॉक पर विचार नहीं करते हैं catch
, जिसे छोड़ा जा सकता है, तो हमारे कोड की 3 पंक्तियां 10 बन जाती हैं। लेकिन हमने मूल रूप से सिर्फ फाइल खोली और 1 लिखा।
3. try
-संसाधनों के साथ
और यहाँ जावा के रचनाकारों ने हम पर कुछ वाक्यगत चीनी छिड़कने का फैसला किया। अपने 7वें संस्करण के साथ शुरू करते हुए, जावा के पास एक नया try
-संसाधनों के साथ कथन है।
close()
विधि को अनिवार्य कॉल के साथ समस्या को हल करने के लिए इसे ठीक से बनाया गया था । सामान्य मामला काफी सरल दिखता है:
try (ClassName name = new ClassName())
{
Code that works with the name variable
}
यह try
कथन का एक और रूपांतर है । आपको कीवर्ड के बाद कोष्ठक जोड़ने की जरूरत है try
, और फिर कोष्ठक के अंदर बाहरी संसाधनों के साथ ऑब्जेक्ट बनाएं। कोष्ठक में प्रत्येक वस्तु के लिए, संकलक विधि finally
में एक खंड और एक कॉल जोड़ता है।close()
नीचे दो समान उदाहरण हैं:
लंबा कोड | कोशिश-के-संसाधनों के साथ कोड |
---|---|
|
|
-with-resources का उपयोग करने वाला कोड try
बहुत छोटा और पढ़ने में आसान है। और हमारे पास जितना कम कोड होगा, टाइपो या अन्य त्रुटि होने की संभावना उतनी ही कम होगी।
वैसे, हम -with-resource स्टेटमेंट में ऐड catch
और finally
ब्लॉक कर सकते हैं। try
या अगर उनकी जरूरत नहीं है तो आप उन्हें नहीं जोड़ सकते।
4. एक ही समय में कई चर
वैसे, आप अक्सर ऐसी स्थिति का सामना कर सकते हैं जब आपको एक ही समय में कई फाइलें खोलने की आवश्यकता होती है। मान लें कि आप एक फ़ाइल की प्रतिलिपि बना रहे हैं, इसलिए आपको दो वस्तुओं की आवश्यकता है: वह फ़ाइल जिससे आप डेटा कॉपी कर रहे हैं और वह फ़ाइल जिसमें आप डेटा कॉपी कर रहे हैं।
इस स्थिति में, try
-with-resources स्टेटमेंट आपको इसमें एक नहीं बल्कि कई ऑब्जेक्ट बनाने देता है। ऑब्जेक्ट बनाने वाले कोड को अर्धविराम से अलग किया जाना चाहिए। यहाँ इस कथन का सामान्य स्वरूप दिया गया है:
try (ClassName name = new ClassName(); ClassName2 name2 = new ClassName2())
{
Code that works with the name and name2 variables
}
फ़ाइलों की प्रतिलिपि बनाने का उदाहरण:
लंबा कोड | लघु कूट संख्या |
---|---|
|
|
अच्छा, हम यहाँ क्या कह सकते हैं? try
-साथ-संसाधन एक अद्भुत चीज है!
5. AutoCloseable
इंटरफ़ेस
लेकिन वह सब नहीं है। चौकस पाठक तुरंत उन कमियों की तलाश करना शुरू कर देगा जो इस कथन को लागू करने के तरीके को सीमित करती हैं।
try
लेकिन अगर कक्षा में कोई विधि नहीं है तो -साथ-संसाधन कथन कैसे काम करता है close()
? ठीक है, मान लीजिए कि कुछ भी नहीं कहा जाएगा। कोई तरीका नहीं, कोई समस्या नहीं।
लेकिन try
-साथ-संसाधन कथन कैसे काम करता है यदि कक्षा में कई close()
विधियां हैं? और उन्हें पारित करने के लिए तर्कों की आवश्यकता है? और कक्षा में close()
पैरामीटर के बिना कोई विधि नहीं है?
मुझे उम्मीद है कि आपने वास्तव में खुद से ये सवाल पूछे हैं, और शायद दूसरों से भी।
ऐसे मुद्दों से बचने के लिए, जावा के निर्माता एक विशेष इंटरफ़ेस के साथ आए AutoCloseable
, जिसे कहा जाता है, जिसमें केवल एक ही तरीका है - close()
जिसमें कोई पैरामीटर नहीं है।
उन्होंने यह प्रतिबंध भी जोड़ा कि केवल लागू होने वाले वर्गों की वस्तुओं कोAutoCloseable
try
संसाधनों के साथ बयान में संसाधनों के रूप में घोषित किया जा सकता है । नतीजतन, ऐसी वस्तुओं में हमेशा एक close()
विधि होगी जिसमें कोई पैरामीटर नहीं होगा।
वैसे, क्या आपको लगता है कि ए try
-रिसोर्स स्टेटमेंट के लिए संसाधन के रूप में घोषित करना संभव है, जिसकी कक्षा में पैरामीटर के बिना अपनी close()
विधि है लेकिन जो लागू नहीं होती है AutoCloseable
?
बुरी खबर: सही उत्तर नहीं है - कक्षाओं को AutoCloseable
इंटरफेस को लागू करना चाहिए।
अच्छी खबर: जावा में बहुत सी कक्षाएं हैं जो इस इंटरफ़ेस को लागू करती हैं, इसलिए यह बहुत संभावना है कि सब कुछ वैसा ही काम करेगा जैसा उसे करना चाहिए।