JavaRush /Java Blog /Random-ID /Rehat kopi #203. Cara menangani pengecualian menggunakan ...

Rehat kopi #203. Cara menangani pengecualian menggunakan pernyataan coba-dengan-sumber daya

Dipublikasikan di grup Random-ID
Sumber: Medium Panduan ini menjelaskan manfaat try-with-resource dibandingkan try-catch-finally. Anda juga akan mempelajari dalam kondisi apa pengecualian yang disembunyikan dilempar dan cara menggunakan sumber daya coba-dengan dengan banyak sumber daya. Rehat kopi #203.  Cara menangani pengecualian menggunakan pernyataan coba-dengan-sumber daya - 1Konstruksi try with resources , juga dikenal sebagai try-with-resources , adalah mekanisme penanganan pengecualian di Java yang dapat secara otomatis menutup sumber daya seperti Java InputStream atau JDBC Connection ketika sudah selesai bekerja dengannya. Pada tahun 2011, Oracle menambahkan coba dengan sumber daya ke sintaks bahasa Java untuk memastikan bahwa objek seperti soket jaringan, koneksi database, dan tautan file dan folder ditutup dengan baik setelah digunakan. Kegagalan untuk menutup sumber daya ini setelah pengembang membuka pegangannya dapat mengakibatkan kebocoran memori, memicu rutinitas pengumpulan sampah yang dapat dicegah, dan overhead CPU pada server.

Sebelum Jawa 7

Di Java, jika Anda menggunakan sumber daya seperti aliran input/output, Anda harus selalu menutupnya setelah digunakan. Karena pengecualian juga dapat dilempar, pengecualian harus dimasukkan ke dalam blok coba-tangkap . Penutupan harus terjadi di blok akhirnya . Setidaknya hal ini terjadi hingga Java 7. Namun memiliki beberapa kelemahan:
  • Anda perlu memeriksa apakah sumber daya Anda nol sebelum menutupnya.
  • Penutupan itu sendiri dapat menimbulkan pengecualian, jadi Anda harus melakukan try-catch lagi di blok Anda .
  • Pemrogram cenderung lupa menutup sumber dayanya.

Bagaimana cara menggunakan pernyataan coba-dengan-sumber daya?

Operator ini awalnya diperkenalkan di Java 7 dan idenya adalah agar pengembang tidak perlu lagi khawatir tentang pengelolaan sumber daya yang mereka gunakan dalam blok try-catch-finally . Hal ini dicapai dengan menghilangkan kebutuhan akan blok akhirnya , yang dalam praktiknya hanya digunakan oleh pengembang untuk menutup sumber daya. Di Java, pernyataan coba-dengan-sumber daya adalah pernyataan coba yang mendeklarasikan satu atau lebih sumber daya. Sumber daya adalah objek yang harus ditutup setelah program berakhir. Ketika eksekusi kode meninggalkan blok coba-dengan-sumber daya , maka sumber daya apa pun yang dibuka di blok coba-dengan-sumber daya akan ditutup secara otomatis, terlepas dari apakah ada pengecualian yang dilemparkan baik dalam blok coba-dengan-sumber daya atau saat mencoba menutup sumber daya . Untuk menggunakan fitur bahasa coba-dengan-sumber daya Java , aturan berikut berlaku:
  • Semua objek yang dikendalikan oleh pernyataan coba-dengan-sumber daya harus mengimplementasikan antarmuka AutoCloseable .
  • Beberapa objek AutoCloseable dapat dibuat di blok coba-dengan-sumber daya .
  • Objek yang dideklarasikan dalam pernyataan try-with-resources dieksekusi dalam blok try , tetapi tidak dalam blok catch atau akhirnya .
  • Metode close() objek yang dideklarasikan dalam blok try-with-resources dipanggil terlepas dari apakah pengecualian dilemparkan pada waktu proses.
  • Jika pengecualian dilempar ke dalam metode close() , pengecualian tersebut dapat diklasifikasikan sebagai pengecualian yang disembunyikan.
Blok tangkapan dan akhirnya masih dapat digunakan dalam blok coba-dengan-sumber daya , dan cara kerjanya sama seperti pada blok coba biasa . Sumber daya yang direferensikan oleh objek AutoCloseable akan selalu ditutup jika coba-dengan-sumber daya digunakan . Hal ini menghilangkan potensi kebocoran memori, yang biasanya disebabkan oleh alokasi sumber daya yang buruk.

Sintaksis

try(declare resources here) {
    // использовать ресурсы
}
catch(FileNotFoundException e) {
    // обработка исключений
}

Penggunaan praktis dari coba-dengan-sumber daya

Untuk menutup secara otomatis, sumber daya harus dideklarasikan dan diinisialisasi di dalam try :
try (PrintWriter writer = new PrintWriter(new File("test.txt"))) {
    writer.println("Hello World");
}

Mengganti try-catch-finally dengan try-with-resources

Cara sederhana dan jelas untuk menggunakan fungsionalitas coba-dengan-sumber daya adalah dengan mengganti blok coba-tangkap-akhirnya yang tradisional dan bertele-tele . Mari kita bandingkan contoh kode berikut. Contoh pertama adalah blok try-catch-finally :
Scanner scanner = null;
try {
    scanner = new Scanner(new File("test.txt"));
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (scanner != null) {
        scanner.close();
    }
}
Dan inilah solusi super ringkas baru menggunakan try-with-resources :
try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

Perbedaan antara mencoba dan mencoba dengan sumber daya

Terkait pengecualian, ada perbedaan antara blok coba-tangkap-akhirnya dan blok coba-dengan-sumber daya . Pengecualian dilemparkan ke dalam blok try dan akhirnya , namun metode ini mengembalikan pengecualian yang dilemparkan hanya di blok akhirnya . Untuk try-with-resources , jika pengecualian terjadi di blok try dan dalam pernyataan try-with-resources , metode akan mengembalikan pengecualian yang dimasukkan ke dalam blok try . Pengecualian yang diberikan oleh blok coba-dengan-sumber daya disembunyikan, artinya, kita dapat mengatakan bahwa blok coba-dengan-sumber daya memunculkan pengecualian yang disembunyikan.

Mengapa saya harus menggunakan pernyataan coba-dengan-sumber daya?

Pernyataan try-with-resources memastikan bahwa setiap sumber daya ditutup pada akhir pernyataan. Jika kita tidak menutup sumber daya, hal ini dapat mengakibatkan kebocoran sumber daya dan program dapat menghabiskan sumber daya yang tersedia. Ini terjadi ketika Anda menggunakan blok try-catch-finally . Sebelum Java SE 7, Anda dapat menggunakan blok akhirnya untuk memastikan bahwa sumber daya akan ditutup terlepas dari apakah pernyataan try keluar secara normal atau tiba-tiba. Contoh berikut menggunakan blok akhirnya dan bukan pernyataan coba-dengan-sumber daya :
static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {

    FileReader fr = new FileReader(path);
    BufferedReader br = new BufferedReader(fr);
    try {
        return br.readLine();
    } finally {
        br.close();
        fr.close();
    }
}
Mungkin ada kebocoran sumber daya dalam contoh ini. Program harus melakukan lebih dari sekedar mengandalkan pengumpul sampah untuk mengosongkan memori sumber daya setelah selesai digunakan. Program juga harus mengembalikan sumber daya ke sistem operasi, biasanya dengan memanggil metode close sumber daya. Namun, jika program tidak melakukan hal ini sebelum pengumpul sampah mengembalikan sumber daya, maka informasi yang diperlukan untuk membebaskan sumber daya tersebut akan hilang. Sumber daya bocor yang dianggap masih digunakan oleh sistem operasi. Pada contoh di atas, jika metode readLine memunculkan pengecualian dan pernyataan br.close() di blok akhirnya memunculkan pengecualian, maka FileReader telah leaked . Inilah sebabnya mengapa Anda lebih baik menggunakan pernyataan coba-dengan-sumber daya daripada blok akhirnya untuk menutup sumber daya program Anda.

Satu contoh lagi

Contoh berikut membaca baris pertama dari sebuah file. Contoh FileReader dan BufferedReader digunakan untuk membaca data . Ini adalah sumber daya yang perlu ditutup setelah program keluar.
import java.io.*;
class Main {
  public static void main(String[] args) {
    String line;
    try(BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
      while ((line = br.readLine()) != null) {
        System.out.println("Line =>"+line);
      }
    } catch (IOException e) {
      System.out.println("IOException in try block =>" + e.getMessage());
    }
  }
}
Seperti yang Anda lihat, sumber daya yang dideklarasikan dalam pernyataan try-with-resources adalah BufferedReader . Pernyataan deklarasi untuk sumber daya ini muncul dalam tanda kurung tepat setelah kata kunci try . Kelas BufferedReader di Java SE 7 dan yang lebih baru mengimplementasikan antarmuka java.lang.AutoCloseable . Karena instance BufferedReader dideklarasikan dalam pernyataan try-with-resource , instance tersebut akan ditutup terlepas dari apakah pernyataan try keluar secara normal atau tiba-tiba (jika metode BufferedReader.readLine() memunculkan IOException ).

Pengecualian yang disembunyikan

Jika blok try memunculkan pengecualian, dan satu atau lebih pengecualian muncul di blok try-with-resources , maka pengecualian yang diberikan oleh blok try-with-resources akan disembunyikan. Dengan kata lain, kita dapat mengatakan bahwa pengecualian yang diberikan oleh try-with-resources adalah pengecualian yang disembunyikan. Anda dapat menangkap pengecualian ini menggunakan metode getSuppress() dari kelas Throwable . Dalam contoh yang ditunjukkan sebelumnya, pengecualian diberikan oleh pernyataan coba-dengan-sumber daya , dalam kondisi berikut:
  • File test.txt tidak ditemukan.
  • Menutup objek BufferedReader .
Pengecualian juga dapat diberikan dari blok try , karena pembacaan file bisa gagal karena berbagai alasan kapan saja. Jika pengecualian dilempar dari blok try dan pernyataan try-with-resources , maka dalam kasus pertama pengecualian dilempar, dan dalam kasus kedua pengecualian tersebut disembunyikan.

Mendapatkan pengecualian yang ditekan

Di Java 7 dan yang lebih baru, pengecualian yang disembunyikan dapat diperoleh dengan memanggil metode Throwable.getSuppressed() dari pengecualian yang diberikan oleh blok try . getSuppress() mengembalikan array yang berisi semua pengecualian yang disembunyikan oleh pernyataan try-with-resources . Jika tidak ada pengecualian yang disembunyikan atau penekanan dinonaktifkan, array kosong akan dikembalikan. Berikut adalah contoh penerimaan pengecualian yang disembunyikan di blok catch :
catch(IOException e) {
  System.out.println("Thrown exception=>" + e.getMessage());
  Throwable[] suppressedExceptions = e.getSuppressed();
  for (int i=0; i" + suppressedExceptions[i]);
  }
}

Manfaat menggunakan sumber daya coba-dengan

  • Kode yang mudah dibaca dan ditulis.
  • Manajemen sumber daya otomatis.
  • Jumlah baris kode telah dikurangi.
  • Ketika beberapa sumber daya dibuka di try-with-resources , sumber daya tersebut ditutup dalam urutan terbalik untuk menghindari masalah ketergantungan.
Dan tentu saja, blok akhirnya tidak lagi diperlukan untuk menutup sumber daya . Sebelumnya, sebelum Java 7, kita harus menggunakan blok akhirnya untuk memastikan bahwa sumber daya ditutup untuk menghindari kebocoran sumber daya. Berikut adalah program yang mirip dengan contoh pertama. Dalam program ini, kami menggunakan blok akhirnya untuk menutup sumber daya.
import java.io.*;
class Main {
  public static void main(String[] args) {
    BufferedReader br = null;
    String line;
    try {
      System.out.println("Entering try block");
      br = new BufferedReader(new FileReader("test.txt"));
      while ((line = br.readLine()) != null) {
        System.out.println("Line =>"+line);
      }
    } catch (IOException e) {
      System.out.println("IOException in try block =>" + e.getMessage());
    } finally {
      System.out.println("Entering finally block");
      try {
        if (br != null) {
          br.close();
        }
      } catch (IOException e) {
        System.out.println("IOException in finally block =>"+e.getMessage());
      }
    }
  }
}
Kesimpulan:
Memasuki blok coba Baris => baris dari file test.txt Memasuki blok akhirnya
Seperti yang dapat Anda lihat dari contoh di atas, penggunaan blok akhirnya untuk membersihkan sumber daya menambah kompleksitas pada kode. Perhatikan blok try...catch di blok akhirnya ? Hal ini karena IOException juga dapat terjadi ketika instance BufferedReader ditutup di dalam blok akhirnya , sehingga juga ditangkap dan ditangani. Pernyataan coba-dengan-sumber daya melakukan manajemen sumber daya otomatis. Kita tidak perlu menutup sumber daya secara eksplisit karena JVM menutupnya secara otomatis. Ini membuat kode lebih mudah dibaca dan ditulis.

Coba-dengan-sumber daya dengan banyak sumber daya

Kita dapat mendeklarasikan banyak sumber daya dalam blok coba-dengan-sumber daya hanya dengan memisahkannya dengan titik koma:
try (Scanner scanner = new Scanner(new File("testRead.txt"));
    PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
    while (scanner.hasNext()) {
	writer.print(scanner.nextLine());
    }
}

Java 9 - Variabel Final yang Efektif

Sebelum Java 9, kita hanya bisa menggunakan variabel baru di dalam blok try-with-resources :
try (Scanner scanner = new Scanner(new File("testRead.txt"));
    PrintWriter writer = new PrintWriter(new File("testWrite.txt"))) {
    // omitted
}
Perhatikan bahwa ini cukup bertele-tele ketika mendeklarasikan banyak sumber daya. Sejak Java 9 (pembaruan JEP 213), kita dapat menggunakan variabel final atau bahkan variabel final secara efektif di dalam blok coba-dengan-sumber daya :
final Scanner scanner = new Scanner(new File("testRead.txt"));
PrintWriter writer = new PrintWriter(new File("testWrite.txt"))
try (scanner;writer) {
    // omitted
}
Sederhananya, suatu variabel secara efektif bersifat final jika tidak diubah setelah penugasan pertama, meskipun variabel tersebut tidak ditandai secara eksplisit final . Seperti yang ditunjukkan di atas, variabel pemindai secara eksplisit dinyatakan final sehingga kita dapat menggunakannya dengan blok coba-dengan-sumber daya . Meskipun variabel writer tidak final secara eksplisit , variabel tersebut tidak berubah setelah penugasan pertama. Jadi kita juga bisa menggunakan variabel penulis . Saya harap hari ini Anda mendapatkan pemahaman yang lebih baik tentang cara menangani pengecualian menggunakan pernyataan coba-dengan-sumber daya . Selamat belajar!
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION