"Amigo, gubuk sepuluh!"

"Saya senang belajar Java, Kapten!"

"Tenang, Amigo. Hari ini kita memiliki topik yang sangat menarik. Kita akan berbicara tentang bagaimana program Java berinteraksi dengan sumber daya eksternal dan kita akan mempelajari satu pernyataan Java yang sangat menarik. Sebaiknya jangan tutup telinga."

"Aku mendengarkan."

"Saat program Java berjalan, terkadang ia berinteraksi dengan entitas di luar mesin Java. Misalnya, dengan file di disk. Entitas ini biasanya disebut sumber daya eksternal."

"Lalu apa yang dianggap sumber daya internal?"

"Sumber daya internal adalah objek yang dibuat di dalam mesin Java. Biasanya, interaksi mengikuti skema ini:

Pernyataan coba-dengan-sumber daya

"Sistem operasi secara ketat melacak sumber daya yang tersedia , dan juga mengontrol akses bersama ke mereka dari program yang berbeda. Misalnya, jika satu program mengubah file, maka program lain tidak dapat mengubah (atau menghapus) file itu. Prinsip ini tidak terbatas pada file, tetapi mereka memberikan contoh yang paling mudah dimengerti.

"Sistem operasi memiliki fungsi (API) yang memungkinkan program memperoleh dan/atau melepaskan sumber daya. Jika sumber daya sibuk, maka hanya program yang memperolehnya yang dapat bekerja dengannya. Jika sumber daya gratis, maka program apa pun dapat memperoleh dia.

“Bayangkan sebuah kantor berbagi mug kopi. Kalau ada yang mengambil mug, maka orang lain tidak bisa lagi mengambilnya. Tapi begitu mug itu digunakan, dicuci, dan diletakkan kembali pada tempatnya, maka siapapun bisa mengambilnya kembali.”

"Mengerti. Ini seperti kursi di kereta bawah tanah atau angkutan umum lainnya. Jika kursi gratis, maka siapa pun dapat mengambilnya. Jika kursi sudah terisi, maka kursi itu dikendalikan oleh orang yang mengambilnya."

"Itu benar. Dan sekarang mari kita bicara tentang memperoleh sumber daya eksternal . Setiap kali program Java Anda mulai bekerja dengan file di disk, mesin Java meminta sistem operasi untuk akses eksklusif ke sana. Jika sumber daya gratis, maka mesin Java memperoleh dia.

"Tetapi setelah Anda selesai bekerja dengan file, sumber daya (file) ini harus dirilis, yaitu Anda perlu memberi tahu sistem operasi bahwa Anda tidak lagi membutuhkannya. Jika Anda tidak melakukan ini, maka sumber daya akan terus menjadi diselenggarakan oleh program Anda."

"Kedengarannya adil."

"Agar tetap seperti itu, sistem operasi menyimpan daftar sumber daya yang ditempati oleh setiap program yang sedang berjalan. Jika program Anda melebihi batas sumber daya yang ditetapkan, maka sistem operasi tidak akan lagi memberi Anda sumber daya baru.

"Ini seperti program yang bisa menghabiskan semua memori..."

"Sesuatu seperti itu. Kabar baiknya adalah jika program Anda dihentikan, semua sumber daya secara otomatis dilepaskan (sistem operasi itu sendiri yang melakukan ini)."

"Jika itu kabar baik, apakah itu berarti ada kabar buruk?"

"Tepat sekali. Berita buruknya adalah jika Anda menulis aplikasi server..."

"Tapi apakah saya menulis aplikasi seperti itu?"

"Banyak aplikasi server ditulis di Java, jadi kemungkinan besar Anda akan menulisnya untuk bekerja. Seperti yang saya katakan, jika Anda menulis aplikasi server, maka server Anda harus berjalan tanpa henti selama berhari-hari, berminggu-minggu, berbulan-bulan, dll."

"Dengan kata lain, program tidak berhenti, dan itu berarti memori tidak dilepaskan secara otomatis."

"Tepat sekali. Dan jika Anda membuka 100 file sehari dan tidak menutupnya, maka dalam beberapa minggu aplikasi Anda akan mencapai batas sumber dayanya dan macet."

"Itu jauh dari pekerjaan stabil selama berbulan-bulan! Apa yang bisa dilakukan?"

"Kelas yang menggunakan sumber daya eksternal memiliki metode khusus untuk melepaskannya: close().

"Ini adalah contoh program yang menulis sesuatu ke file dan kemudian menutup file setelah selesai, yaitu membebaskan sumber daya sistem operasi. Kira-kira seperti ini:

Kode Catatan
String path = "c:\\projects\\log.txt";
FileOutputStream output = new FileOutputStream(path);
output.write(1);
output.close();
Jalur ke file.
Dapatkan objek file: dapatkan sumber daya.
Tulis ke file
Tutup file - lepaskan sumber daya

"Ah... Jadi, setelah bekerja dengan file (atau sumber daya eksternal lainnya), saya harus memanggil metode close()pada objek yang ditautkan ke sumber daya eksternal."

"Ya. Semuanya tampak sederhana. Tapi pengecualian bisa terjadi saat program berjalan, dan sumber daya eksternal tidak akan dirilis."

"Dan itu sangat buruk. Apa yang harus dilakukan?"

"Untuk memastikan bahwa close()metode selalu dipanggil, kita perlu membungkus kode kita dalam blok try- catch- finallydan menambahkan close()metode ke finallyblok. Ini akan terlihat seperti ini:

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

"Hmm... Ada yang salah di sini?"

"Benar. Kode ini tidak dapat dikompilasi, karena outputvariabel dideklarasikan di dalam try{}blok, dan karena itu tidak terlihat di finallyblok.

Mari kita perbaiki:

FileOutputStream output = new FileOutputStream(path);

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

"Apakah semuanya baik-baik saja sekarang?"

"Tidak apa-apa, tapi itu tidak akan berhasil jika terjadi kesalahan saat kita membuat objek FileOutputStream, dan ini bisa terjadi dengan mudah.

Mari kita perbaiki:

FileOutputStream output = null;

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

"Dan apakah semuanya bekerja sekarang?"

“Masih ada sedikit kritik. Pertama, jika terjadi kesalahan saat membuat objek FileOutputStream, maka outputvariabelnya akan menjadi null. Kemungkinan ini harus diperhitungkan dalam finallyblok.

"Kedua, close()metode ini selalu dipanggil di finallyblok, yang artinya tidak perlu di tryblok. Kode terakhir akan terlihat seperti ini:

FileOutputStream output = null;

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

"Bahkan jika kami tidak mempertimbangkan catchblok, yang dapat dihilangkan, maka 3 baris kode kami menjadi 10. Tapi pada dasarnya kami hanya membuka file dan menulis 1."

"Fiuh... Ini hal yang baik untuk menyimpulkan masalah ini. Relatif bisa dimengerti, tapi agak membosankan, bukan?"

"Begitulah. Itu sebabnya pembuat Java membantu kami dengan menambahkan beberapa gula sintaksis. Sekarang mari beralih ke sorotan program, atau lebih tepatnya, pelajaran ini:

try-dengan-sumber daya

"Dimulai dengan versi ke-7, Java memiliki trypernyataan -with-resources baru.

"Itu dibuat tepat untuk memecahkan masalah dengan pemanggilan wajib ke metode close()."

"Kedengarannya menjanjikan!"

"Kasus umum terlihat cukup sederhana:

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

"Jadi ini variasi lain dari try pernyataan itu ?"

"Ya. Anda perlu menambahkan tanda kurung setelah trykata kunci, lalu membuat objek dengan sumber daya eksternal di dalam tanda kurung. Untuk setiap objek dalam tanda kurung, kompiler menambahkan bagian finallydan panggilan ke close()metode.

"Di bawah ini adalah dua contoh yang setara:

Kode panjang Kode dengan coba-dengan-sumber daya
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);
}

"Keren! Kode yang menggunakan try-with-resources jauh lebih pendek dan lebih mudah dibaca. Dan semakin sedikit kode yang kita miliki, semakin kecil kemungkinan salah ketik atau kesalahan lainnya."

"Saya senang Anda menyukainya. Omong-omong, kami dapat menambah catchdan finallymemblokir trypernyataan -with-resources. Atau Anda tidak dapat menambahkannya jika tidak diperlukan.

Beberapa variabel sekaligus

"Anda mungkin sering menghadapi situasi ketika Anda perlu membuka beberapa file pada saat yang sama. Katakanlah Anda sedang menyalin file, jadi Anda memerlukan dua objek: file tempat Anda menyalin data dan file tempat Anda menyalin data .

"Dalam hal ini, trypernyataan -with-resources memungkinkan Anda membuat satu tetapi beberapa objek di dalamnya. Kode yang membuat objek harus dipisahkan dengan titik koma. Berikut tampilan umum dari pernyataan ini:

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

Contoh menyalin file:

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

"Yah, apa yang bisa kita katakan di sini? try-dengan-sumber daya adalah hal yang luar biasa!"

"Apa yang bisa kita katakan adalah kita harus menggunakannya."