1. Əlavə resurslar
Bəzən Java-proqram işləyərkən Java-maşınından kənarda olan obyektlərlə qarşılıqlı əlaqədə olur. Məsələn, diskdəki fayllarla. Belə obyektlər adətən əlavə resurslar adlanır. Daxili resurslar - Java-maşını daxilində yaradılan obyektlərdir.
Adətən qarşılıqlı əlaqə aşağıdakı sxemlə həyata keçirilir:
Resursların uçotu
Əməliyyat sistemi mövcud resursların ciddi uçotunu aparır, həmçinin müxtəlif proqramların onlara birgə müraciətinə nəzarət edir. Məsələn, əgər bir proqram hansısa faylı dəyişirsə, başqa bir proqram həmin faylı dəyişə (və ya silə) bilməz. Bu yalnız fayllara aid deyil, lakin onları nümunə kimi götürmək daha aydın olar.
Əməliyyat sistemində proqramlara hansısa resursu tutmaq və/və ya azad etmək imkanı verən funksiyalar (API) mövcuddur. Əgər resurs tutulubsa, onu yalnız tutmuş proqram istifadə edə bilər. Əgər resurs azaddırsa, istənilən proqram onu tuta bilər.
Təsəvvür edin ki, ofisdə ümumi fincanlar var. Kimsə bir fincanı götürəndə, artıq başqa biri onu götürə bilməz. Amma istifadə edib, yuyub yerinə qoyandan sonra, artıq onu kim istəsə götürə bilər. Və ya metroda və ya marşrutkada yer. Əgər yer azaddırsa, istənilən şəxs onu tuta bilər. Əgər yer tutulubsa, artıq yalnız onu tutan şəxs nəzarət edir.
Əlavə resursların tutulması
Java-proqramınız hər dəfə diskdəki hansısa faylla işləməyə başladıqda, Java-maşını əməliyyat sistemindən bu fayla müstəsna giriş istəyir. Əgər resurs azaddırsa, onu Java-maşını tutur.
Ama faylla işinizi bitirdikdən sonra, həmin resursu (faylı) azad etmək lazımdır: əməliyyat sisteminə bildirmək lazımdır ki, artıq o sizə lazım deyil. Əgər bunu etməsəniz, resurs proqramınıza aid olaraq qalmağa davam edəcək.
Əməliyyat sistemi işləyən hər bir proqram üçün tutulan resursların siyahısını aparır. Əgər proqramınız ona verilən resurs limitini aşsa, artıq yeni resurslar əməliyyat sistemi tərəfindən sizə verilməyəcək.
Yaxşı xəbər odur ki, əgər proqramınız başa çatarsa, bütün resurslar avtomatik olaraq azad edilir (bunu əməliyyat sistemi özü edir).
Pis xəbər isə odur ki, əgər siz server tətbiqi yazırsınızsa (və bir çox server tətbiqləri Java-da yazılır), sizin serveriniz günlərlə, həftələrlə, aylarla fasiləsiz işləməlidir. Və əgər gün ərzində 100 fayl açıb onları bağlamırsınızsa, bir neçə həftə sonra tətbiqiniz öz limitini aşacaq və dayanacaq. Bu isə aylarla stabil işləyən sistemə oxşamır.
2. close()
metodu
Xarici resurslardan istifadə edən siniflərin, onları azad etmək üçün xüsusi bir metodu var — close()
.
Aşağıda fayla nəsə yazıb sonra faylı bağlayan bir proqram nümunəsi verilmişdir – əməliyyat sisteminin resurslarını azad edir. Təxminən belə görünür:
Kod | Qeyd |
---|---|
|
Faylın yolu. Fayl obyektini alırıq: resursu götürürük. Fayla yazırıq Faylı bağlayırıq — resursu azad edirik. |
Faylla (və ya digər xarici resurslarla) işlədikdən sonra, xarici resursla əlaqəli olan obyektin close()
metodunu çağırmalısınız.
İstisnalar
Hər şey sadə görünür. Amma proqram işləyərkən istisnalar yarana bilər və xarici resurs heç bir zaman azad olunmaz. Bu, çox pisdir.
close()
metodu həmişə çağırılsın deyə, kodumuzu try
-catch
-finally
blokuna yığıb, close()
metodunu finally
blokuna əlavə etmək lazımdır. Bu şəkildə görünəcək:
try
{
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
Bu kod kompilyasiya olunmayacaq, çünki output
dəyişəni try {}
blokunda elan edilib, bu səbəbdən finally
blokunda görünmür.
Düzəldirik:
FileOutputStream output = new FileOutputStream(path);
try
{
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
Yaxşı, amma işləməyəcək, əgər FileOutputStream
obyekti yaradılarkən bir səhv baş versə, bu, çox asanlıqla ola bilər.
Yenidən düzəliş edirik:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
Hələ də bir neçə qeyd var. Birincisi, əgər FileOutputStream
obyekti yaradılarkən bir səhv baş versə, output
dəyişəni null olacaq və bu faktı finally
blokunda nəzərə almaq lazımdır.
İkincisi, finally
blokunda olan close()
metodu həmişə çağırılır, buna görə də try
blokunda ona ehtiyac yoxdur. Son kod belə görünəcək:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (output != null)
output.close();
}
Əgər catch
blokunu nəzərə almasaq belə, kodumuz üç sətirdən 10 sətirə çevrildi. Halbuki əslində biz sadəcə faylı açıb oraya 1 yazdıq. Bir qədər həcmli deyilmi?
3. try
-with-resources
Java-nı yaradanlar bu yerdə də bir az sintaktik "şirinlik" əlavə etməyə qərar verdilər. Java 7-ci versiyasından başlayaraq, bu yeni try
-with-resources (try
ilə resurslar) operatoru əlavə olundu.
Bu operator, əsasən, close()
metodunun çağırılması problemini həll etmək üçün yaradılıb. Əsas görünüşü belədir:
try (Sinif ad = new Sinif())
{
Dəyişənlə işləyən kod ad
}
Bu, operator try
-nin başqa bir variantıdır. try
açar sözündən sonra dairəvi mötərizələr əlavə etməlisiniz və onların içərisində xarici resurslarla obyektlər yaratmalısınız. Dairəvi mötərizələrdə göstərilən obyekt üçün kompilyator özü finally
bölməsi və close()
metodunun çağırılmasını əlavə edəcək.
Aşağıda iki ekvivalent nümunə göstərilib:
Uzun kod | try-with-resources ilə kod |
---|---|
|
|
try
-with-resources istifadəsi ilə kod daha qısa və oxunaqlıdır. Və nə qədər az kod varsa, səhv etmək şansı bir o qədər azdır.
Bununla yanaşı, try
-with-resources operatoruna catch
və finally
blokları əlavə etmək mümkündür. Onları əlavə etmək məcburi deyil, əgər ehtiyac yoxdursa.
4. Bir neçə dəyişəni eyni anda istifadə etmək
Məsələn, belə bir vəziyyət meydana çıxa bilər ki, birdən çox faylı eyni anda açmağa ehtiyacınız var. Tutaq ki, bir faylı kopyalayırıq və sizə iki obyekt lazımdır: məlumatları kopyaladığınız fayl və məlumatları kopyaladığınız fayl.
Bu hal üçün try
-with-resources operatoru bir obyekt deyil, bir neçə obyekt yaratmağa icazə verir. Obyektlərin yaradılma kodu nöqtəli vergül ilə ayrılmalıdır. Ümumi görünüşü belədir:
try (Class name = new Class(); Class2 name2 = new Class2())
{
name və name2 dəyişəni ilə işləyən kod
}
Faylların kopyalanmasının nümunəsi:
Uzun kod | Qısa kod |
---|---|
|
|
Ümumilikdə, nə deyək: bu try
-with-resources çox əla bir şeydir.
5. AutoCloseable
interfeysi
Amma hələ də hamısı bu deyil. Diqqətli oxucu dərhal bu operatorun tətbiq hüdudunda bir şübhə axtaracaq.
Bəs əgər sinifdə close()
metodu yoxdursa, try
-with-resources operatoru necə işləyəcək? Yaxşı, onda heç nə çağırılmayacaq. Metod yoxdursa, problem də yoxdur.
Bəs əgər sinifin bir neçə close()
metodu varsa? Və onlara parametrlər ötürmək lazımdır? Və əgər sinifin parametrsiz close()
metodu yoxdursa?
Ümid edirəm ki, siz həqiqətən bu sualları özünüzə verdiniz, və bəlkə də daha çoxunu da.
Bu cür sualların olmaması üçün Java-nın yaradıcıları xüsusi bir sinif (interfeys) AutoCloseable
fikirləşiblər ki, burada yalnız bir metod var – parametrlərsiz close()
.
Həmçinin məhdudlaşdırma da əlavə olunub ki, try
-with-resources daxilində resurs olaraq yalnız AutoCloseable
-dan irəli gələn siniflərin obyektlərini istifadə etmək olar. Beləliklə, bu obyektlərin həmişə parametrlərsiz close()
metodu olacaq.
Bu arada, sizcə, resurs kimi sinfin parametrlərsiz close()
metodu olan, amma AutoCloseable
-dan irəli gəlməyən obyektini try
-with-resources daxilində istifadə etmək olarmı?
Pis xəbər: doğru cavab – yox, siniflər mütləq AutoCloseable
interfeysini reallaşdırmalıdır.
Yaxşı xəbər: Java-da çox sayda sinif bu interfeysi reallaşdırır, beləliklə, yüksək ehtimalla hər şey lazım olduğu kimi işləyəcək.
GO TO FULL VERSION