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:

Kaynaklarla dene bildirimi

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
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
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- finallybloğ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();
}

outputDeğ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 FileOutputStreamve 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 outputnull 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 tryve ardından parantez içinde harici kaynaklara sahip nesneler oluşturmanız gerekir. Parantez içindeki her nesne için derleyici, yönteme bir finallybö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
FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
}
finally
{
   if (output != null)
   output.close();
}
try(FileOutputStream output = new FileOutputStream(path))
{
   output.write(1);
}

-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 catchve finallyengellemeler 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
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

FileInputStream input = null;
FileOutputStream output = null;

try
{
   input = new FileInputStream(src);
   output = new FileOutputStream(dest);

   byte[] buffer = input.readAllBytes();
   output.write(buffer);
}
finally
{
   if (input != null)
      input.close();
   if (output != null)
      output.close();
}
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileInputStream input = new FileInputStream(src);

FileOutputStream output = new FileOutputStream(dest))
{
   byte[] buffer = input.readAllBytes();
   output.write(buffer);
}

Peki, burada ne söyleyebiliriz? try-kaynaklarla-harika bir şey!


5. AutoCloseablearayüz

Ama hepsi bu kadar değil. Dikkatli okuyucu, hemen bu ifadenin nasıl uygulanabileceğini sınırlayan tuzaklar aramaya başlayacaktır.

tryAncak , 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.

tryAncak , 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 AutoCloseableyalnı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 trybir 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.