1. Dış kaynaklar
Bir Java programı çalışırken, bazen Java makinesinin dışındaki varlıklarla etkileşime girer. Örneğin, diskteki dosyalarla. Bu varlıklara genellikle dış kaynaklar denir. İç kaynaklar, Java makinesinde oluşturulan nesnelerdir.
Tipik olarak, etkileşim şu şemayı takip eder:
Kaynakları izleme
İşletim sistemi, mevcut kaynakları titizlikle takip eder ve ayrıca farklı programlardan bu kaynaklara paylaşılan erişimi denetler. Örneğin, bir program bir dosyayı değiştirirse, başka bir program o dosyayı değiştiremez (veya silemez). Bu ilke dosyalarla sınırlı değildir, ancak en kolay anlaşılır örneği sağlarlar.
İşletim sistemi, bir programın kaynakları almasına ve/veya serbest bırakmasına izin veren işlevlere (API'ler) sahiptir. Bir kaynak meşgulse, yalnızca onu edinen program onunla çalışabilir. Bir kaynak ücretsizse, herhangi bir program onu alabilir.
Ofisinizde ortak kahve kupaları olduğunu hayal edin. Birisi bir kupa alırsa, diğer insanlar artık onu alamazlar. Ancak kupa kullanıldıktan, yıkandıktan ve yerine konduktan sonra herkes onu tekrar alabilir. Bir otobüs veya metrodaki koltuklarla durum aynıdır. Bir koltuk boşsa, o zaman herkes alabilir. Bir koltuk doluysa, onu alan kişi tarafından kontrol edilir.
Dış kaynakların alınması .
Java programınız diskteki bir dosyayla her çalışmaya başladığında, Java makinesi işletim sisteminden dosyaya özel erişim ister. Kaynak ücretsizse, Java makinesi onu alır.
Ancak dosyayla çalışmayı bitirdikten sonra, bu kaynak (dosya) serbest bırakılmalıdır, yani işletim sistemine artık ona ihtiyacınız olmadığını bildirmeniz gerekir. Bunu yapmazsanız, kaynak programınız tarafından tutulmaya devam edecektir.
İşletim sistemi, çalışan her program tarafından kullanılan kaynakların bir listesini tutar. Programınız atanan kaynak sınırını aşarsa, işletim sistemi artık size yeni kaynaklar vermeyecektir.
İyi haber şu ki, programınız sona ererse, tüm kaynaklar otomatik olarak serbest bırakılır (bunu işletim sisteminin kendisi yapar).
Kötü haber şu ki, bir sunucu uygulaması yazıyorsanız (ve birçok sunucu uygulaması Java ile yazılmıştır), sunucunuzun günlerce, haftalarca ve aylarca durmadan çalışabilmesi gerekir. Günde 100 dosya açar ve kapatmazsanız, birkaç hafta içinde uygulamanız kaynak sınırına ulaşacak ve çökecektir. Bu, aylarca süren istikrarlı çalışmanın çok gerisinde kalıyor.
2. close()
yöntem
Dış kaynakları kullanan sınıfların, bunları serbest bırakmak için özel bir yöntemi vardır: close()
.
Aşağıda, bir dosyaya bir şeyler yazan ve bittiğinde dosyayı kapatan, yani işletim sisteminin kaynaklarını serbest bırakan bir program örneği sunuyoruz. Şuna benzer:
kod | Not |
---|---|
|
Dosyanın yolu. Dosya nesnesini alın: kaynağı edinin. Dosyaya yaz Dosyayı kapat - kaynağı serbest bırak |
Bir dosyayla (veya diğer dış kaynaklarla) çalıştıktan sonra, yöntemi close()
dış kaynağa bağlı nesne üzerinde çağırmanız gerekir.
İstisnalar
Her şey basit görünüyor. Ancak bir program çalışırken istisnalar oluşabilir ve dış kaynak serbest bırakılmaz. Ve bu çok kötü.
Yöntemin her zaman çağrıldığından emin olmak için close()
, kodumuzu bir try
- catch
- finally
bloğa sarmamız ve close()
yöntemi bloğa eklememiz gerekir finally
. Bunun gibi bir şey görünecek:
try
{
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
output
Değişken bloğun içinde bildirildiğinden try {}
ve bu nedenle blokta görünmediğinden bu kod derlenmeyecektir finally
.
Düzeltelim:
FileOutputStream output = new FileOutputStream(path);
try
{
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
Sorun değil, ancak nesneyi oluşturduğumuzda bir hata oluşursa çalışmaz FileOutputStream
ve bu oldukça kolay olabilir.
Düzeltelim:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
output.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
output.close();
}
Hala birkaç eleştiri var. İlk olarak, nesne oluşturulurken bir hata oluşursa FileOutputStream
, değişken output
null olacaktır. Bu olasılık blokta hesaba katılmalıdır finally
.
İkincisi, close()
yöntem her zaman blokta çağrılır finally
, yani blokta gerekli değildir try
. Nihai kod şöyle görünecektir:
FileOutputStream output = null;
try
{
output = new FileOutputStream(path);
output.write(1);
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (output != null)
output.close();
}
Atlanabilecek bloğu dikkate almasak bile catch
, o zaman 3 satırımız 10 olur. Ama temelde dosyayı açıp 1 yazdık. Biraz hantal değil mi?
3. try
-kaynaklarla-
Ve burada Java'nın yaratıcıları üzerimize biraz sözdizimsel şeker serpmeye karar verdiler. Java'nın 7. sürümünden itibaren yeni bir try
-with-resources ifadesi vardır.
Yönteme zorunlu çağrı ile sorunu tam olarak çözmek için yaratılmıştır close()
. Genel durum oldukça basit görünüyor:
try (ClassName name = new ClassName())
{
Code that works with the name variable
}
try
Bu, ifadenin başka bir varyasyonudur . Anahtar kelimeden sonra parantez eklemeniz try
ve ardından parantez içinde harici kaynaklara sahip nesneler oluşturmanız gerekir. Parantez içindeki her nesne için derleyici, yönteme bir finally
bölüm ve bir çağrı ekler close()
.
Aşağıda iki eşdeğer örnek verilmiştir:
uzun kod | try-with-resources içeren kod |
---|---|
|
|
-with-resources kullanan kod try
çok daha kısadır ve okunması daha kolaydır. Ve ne kadar az kodumuz olursa, yazım hatası veya başka bir hata yapma şansımız o kadar az olur.
Bu arada, -with-resources ifadesine eklemeler catch
ve finally
engellemeler yapabiliriz try
. Veya gerekli değilse ekleyemezsiniz.
4. Aynı anda birkaç değişken
Bu arada, aynı anda birkaç dosya açmanız gerektiğinde, genellikle bir durumla karşılaşabilirsiniz. Diyelim ki bir dosyayı kopyalıyorsunuz, dolayısıyla iki nesneye ihtiyacınız var: verileri kopyaladığınız dosya ve verileri kopyaladığınız dosya.
Bu durumda, try
-with-resources deyimi, içinde bir ama birkaç nesne oluşturmanıza izin verir. Nesneleri oluşturan kod noktalı virgülle ayrılmalıdır. İşte bu ifadenin genel görünümü:
try (ClassName name = new ClassName(); ClassName2 name2 = new ClassName2())
{
Code that works with the name and name2 variables
}
Dosya kopyalama örneği:
uzun kod | Kısa kod |
---|---|
|
|
Peki, burada ne söyleyebiliriz? try
-kaynaklarla-harika bir şey!
5. AutoCloseable
arayüz
Ama hepsi bu kadar değil. Dikkatli okuyucu, hemen bu ifadenin nasıl uygulanabileceğini sınırlayan tuzaklar aramaya başlayacaktır.
try
Ancak , sınıfın bir yöntemi yoksa -with-resources ifadesi nasıl çalışır close()
? Pekala, hiçbir şeyin aranmayacağını varsayalım. Yöntem yok, sorun yok.
try
Ancak , sınıfın birkaç yöntemi varsa, -with-resources ifadesi nasıl çalışır close()
? Ve onlara iletilecek argümanlara mı ihtiyaçları var? close()
Ve sınıfın parametresiz bir yöntemi yok mu ?
Umarım kendinize bu soruları ve belki de başkalarını gerçekten sormuşsunuzdur.
Bu tür sorunlardan kaçınmak için, Java'nın yaratıcıları, parametresi olmayan AutoCloseable
yalnızca bir yöntemi olan - adında özel bir arabirim geliştirdiler .close()
Ayrıca, -with-resources deyiminde yalnızca uygulayan sınıfların nesnelerininAutoCloseable
kaynak olarak bildirilebileceği kısıtlamasını da eklediler try
. close()
Sonuç olarak, bu tür nesnelerin her zaman parametresiz bir yöntemi olacaktır .
Bu arada, -with-resources deyiminin, sınıfının parametresiz kendi yöntemi olan ancak uygulamayan try
bir nesneyi kaynak olarak bildirmesinin mümkün olduğunu düşünüyor musunuz ?close()
AutoCloseable
Kötü haber: Doğru cevap hayır — sınıfların arabirimi uygulaması gerekir AutoCloseable
.
İyi haber: Java'da bu arabirimi uygulayan birçok sınıf vardır, bu nedenle her şeyin olması gerektiği gibi çalışması çok olasıdır.