"Amigo, sepuluh pondok!"

"Saya gembira dapat belajar bahasa Jawa, Kapten!"

"Tenang, Amigo. Hari ini kita mempunyai topik yang sangat menarik. Kita akan bercakap tentang cara program Java berinteraksi dengan sumber luaran dan kita akan mengkaji satu pernyataan Java yang sangat menarik. Lebih baik jangan tutup telinga anda."

"Saya semua telinga."

"Semasa program Java berjalan, kadangkala ia berinteraksi dengan entiti di luar mesin Java. Contohnya, dengan fail pada cakera. Entiti ini biasanya dipanggil sumber luaran."

"Kemudian apakah yang dianggap sebagai sumber dalaman?"

"Sumber dalaman ialah objek yang dibuat di dalam mesin Java. Biasanya, interaksi mengikut skema ini:

Pernyataan cuba-dengan-sumber

"Sistem pengendalian dengan teliti menjejaki sumber yang tersedia , dan juga mengawal akses dikongsi kepada mereka daripada program yang berbeza. Contohnya, jika satu program menukar fail, maka program lain tidak boleh menukar (atau memadam) fail itu. Prinsip ini bukan terhad kepada fail, tetapi ia memberikan contoh yang paling mudah difahami.

"Sistem pengendalian mempunyai fungsi (API) yang membenarkan program memperoleh dan/atau melepaskan sumber. Jika sumber sibuk, maka hanya program yang memperolehnya boleh berfungsi dengannya. Jika sumber percuma, maka mana-mana program boleh memperoleh ia.

"Bayangkan pejabat telah berkongsi cawan kopi. Jika seseorang mengambil mug, maka orang lain tidak boleh mengambilnya lagi. Tetapi apabila mug itu digunakan, dicuci dan diletakkan semula di tempatnya, maka sesiapa pun boleh mengambilnya semula."

"Faham. Ia seperti tempat duduk di kereta bawah tanah atau pengangkutan awam lain. Jika tempat duduk percuma, sesiapa sahaja boleh mengambilnya. Jika tempat duduk itu diduduki, maka ia dikawal oleh orang yang mengambilnya."

"Betul. Dan sekarang mari kita bincangkan tentang memperoleh sumber luaran . Setiap kali program Java anda mula berfungsi dengan fail pada cakera, mesin Java meminta sistem pengendalian untuk akses eksklusif kepadanya. Jika sumber itu percuma, maka mesin Java memperoleh ia.

"Tetapi selepas anda selesai bekerja dengan fail, sumber (fail) ini mesti dikeluarkan, iaitu anda perlu memberitahu sistem pengendalian bahawa anda tidak lagi memerlukannya. Jika anda tidak melakukan ini, maka sumber itu akan terus menjadi diadakan oleh program anda."

"Bunyinya adil."

"Untuk memastikannya begitu, sistem pengendalian mengekalkan senarai sumber yang diduduki oleh setiap program yang sedang berjalan. Jika program anda melebihi had sumber yang ditetapkan, maka sistem pengendalian tidak akan memberi anda sumber baharu lagi.

"Ia seperti program yang boleh memakan semua memori..."

"Sesuatu seperti itu. Berita baiknya ialah jika program anda ditamatkan, semua sumber dikeluarkan secara automatik (sistem pengendalian itu sendiri melakukan ini)."

"Jika itu berita baik, adakah itu bermakna ada berita buruk?"

"Begitu juga. Berita buruknya ialah jika anda menulis aplikasi pelayan..."

"Tetapi adakah saya menulis aplikasi sedemikian?"

"Banyak aplikasi pelayan ditulis dalam Java, jadi kemungkinan besar anda akan menulisnya untuk kerja. Seperti yang saya katakan, jika anda menulis aplikasi pelayan, maka pelayan anda perlu berjalan tanpa henti selama beberapa hari, minggu, bulan, dan lain-lain."

"Dalam erti kata lain, program ini tidak ditamatkan, dan ini bermakna memori tidak dikeluarkan secara automatik."

"Tepat sekali. Dan jika anda membuka 100 fail sehari dan tidak menutupnya, maka dalam beberapa minggu aplikasi anda akan mencapai had sumber dan ranapnya."

"Itu semakin berkurangan untuk bekerja yang stabil selama berbulan-bulan! Apa yang boleh dilakukan?"

"Kelas yang menggunakan sumber luaran mempunyai kaedah khas untuk melepaskannya: close().

"Berikut ialah contoh program yang menulis sesuatu pada fail dan kemudian menutup fail apabila ia selesai, iaitu ia membebaskan sumber sistem pengendalian. Ia kelihatan lebih kurang seperti ini:

Kod Catatan
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
Laluan ke fail.
Dapatkan objek fail: peroleh sumber.
Tulis pada fail
Tutup fail - lepaskan sumber

"Ah... Jadi, selepas bekerja dengan fail (atau sumber luaran lain), saya perlu memanggil kaedah close()pada objek yang dipautkan kepada sumber luaran."

"Ya. Semuanya nampak mudah. ​​Tetapi pengecualian boleh berlaku semasa program berjalan dan sumber luaran tidak akan dikeluarkan."

"Dan itu sangat teruk. Apa yang perlu dilakukan?"

"Untuk memastikan close()kaedah itu sentiasa dipanggil, kami perlu membungkus kod kami dalam try- catch- finallyblok dan menambah close()kaedah pada finallyblok. Ia akan kelihatan seperti ini:

try
{
   FileOutputStream output = new FileOutputStream(path);
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"Hmm... Ada apa-apa ke?"

"Betul. Kod ini tidak akan disusun, kerana outputpembolehubah diisytiharkan di dalam try{}blok, dan oleh itu tidak kelihatan dalam finallyblok.

Mari kita betulkan:

FileOutputStream output = new FileOutputStream(path);

try
{
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"Adakah semuanya baik sekarang?"

"Tidak mengapa, tetapi ia tidak akan berfungsi jika ralat berlaku semasa kami mencipta FileOutputStreamobjek, dan ini boleh berlaku dengan mudah.

Mari kita betulkan:

FileOutputStream output = null;

try
{
   output = new FileOutputStream(path);
   output.write(1);
   output.close();
}
catch (IOException e)
{
   e.printStackTrace();
}
finally
{
   output.close();
}

"Dan adakah semuanya berfungsi sekarang?"

"Masih terdapat sedikit kritikan. Pertama, jika ralat berlaku semasa mencipta FileOutputStreamobjek, maka outputpembolehubah akan menjadi batal. Kemungkinan ini mesti diambil kira dalam finallyblok.

"Kedua, close()kaedah ini sentiasa dipanggil dalam finallyblok, yang bermaksud bahawa ia tidak perlu dalam tryblok. Kod akhir akan kelihatan seperti ini:

FileOutputStream output = null;

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

"Walaupun kami tidak menganggap catchblok itu, yang boleh ditinggalkan, maka 3 baris kod kami menjadi 10. Tetapi pada dasarnya kami hanya membuka fail dan menulis 1."

"Fuh... Ia adalah perkara yang baik untuk menyimpulkan perkara itu. Agak boleh difahami, tetapi agak membosankan, bukan?"

"Begitu juga. Itulah sebabnya pencipta Java membantu kami dengan menambahkan beberapa gula sintaksis. Sekarang mari kita beralih ke sorotan program, atau lebih tepatnya, pelajaran ini:

try-dengan-sumber

"Bermula dengan versi ke-7nya, Java mempunyai trypernyataan -dengan-sumber yang baharu.

"Ia dicipta dengan tepat untuk menyelesaikan masalah dengan panggilan wajib kepada close()kaedah itu."

"Bunyinya menjanjikan!"

"Kes umum kelihatan agak mudah:

try (ClassName name = new ClassName())
{
   Code that works with the name variable
}

"Jadi ini adalah satu lagi variasi try pernyataan itu ?"

"Ya. Anda perlu menambah kurungan selepas trykata kunci, dan kemudian mencipta objek dengan sumber luaran di dalam kurungan. Untuk setiap objek dalam kurungan, pengkompil menambah bahagian finallydan panggilan ke close()kaedah.

"Di bawah adalah dua contoh yang setara:

Kod panjang Kod dengan cuba-dengan-sumber
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);
}

"Cool! Kod yang menggunakan try-with-resources adalah lebih pendek dan lebih mudah dibaca. Dan semakin kurang kod yang kita ada, semakin kurang peluang untuk membuat kesilapan menaip atau ralat lain."

"Saya gembira anda menyukainya. Dengan cara ini, kami boleh menambah catchdan finallymenyekat trykenyataan -dengan-sumber. Atau anda tidak boleh menambahnya jika ia tidak diperlukan.

Beberapa pembolehubah pada masa yang sama

"Anda mungkin sering menghadapi situasi apabila anda perlu membuka beberapa fail pada masa yang sama. Katakan anda menyalin fail, jadi anda memerlukan dua objek: fail dari mana anda menyalin data dan fail yang anda menyalin data .

"Dalam kes ini, trypernyataan -with-resources membolehkan anda mencipta satu tetapi beberapa objek di dalamnya. Kod yang mencipta objek mesti dipisahkan dengan koma bertitik. Berikut ialah penampilan umum pernyataan ini:

try (ClassName name = new ClassName(); ClassName2 name2 = new ClassName2())
{
   Code that works with the name and name2 variables
}

Contoh menyalin fail:

Kod pendek Kod panjang
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);
}
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();
}

"Nah, apa yang boleh kita katakan di sini? try-dengan-sumber adalah perkara yang menarik!"

"Apa yang boleh kami katakan ialah kami harus menggunakannya."