melempar pengecualian runtime dalam aplikasi Java

12

Saya bekerja sebagai kontraktor yang merancang aplikasi Java perusahaan untuk klien saya dalam peran sebagai pimpinan teknis. Aplikasi akan digunakan oleh pengguna akhir dan akan ada tim pendukung yang akan mendukung aplikasi ketika kita pergi.

Petunjuk teknis lainnya dengan siapa saya bekerja berada di bawah kesan bahwa penanganan pengecualian akan membuat kode kotor. Sistem harus membuang pengecualian yang dicentang hanya dari tingkat Layanan dan sisa kode harus membuang pengecualian runtime dari semua tingkatan lainnya sehingga tidak perlu menangani pengecualian yang tidak dicentang.

Apa yang perlu dilemparkan dari pengecualian pada aplikasi bisnis?

Dari pengalaman saya di masa lalu tentang pengecualian runtime:

1) Pengecualian yang tidak dicentang membuat kode tidak dapat diprediksi karena tidak muncul bahkan di Javadoc.

2) Melempar Pengecualian yang tidak dicentang dalam aplikasi bisnis tidak masuk akal karena ketika Anda melemparkannya dan langsung masuk ke wajah Pengguna, bagaimana Anda menjelaskannya kepada pengguna? Saya sudah cukup banyak melihat aplikasi web yang menunjukkan 500 -Internal Error. Contact Administratorapa-apa bagi pengguna akhir atau tim pendukung yang mengelola aplikasi.

3) Melempar pengecualian runtime memaksa pengguna kelas melempar pengecualian untuk berjalan melalui kode sumber untuk debug dan melihat mengapa pengecualian dilemparkan. Ini hanya dapat dihindari jika Javadoc dari pengecualian runtime didokumentasikan dengan sangat baik yang saya temukan tidak pernah menjadi kasus.

randominstanceOfLivingThing
sumber
Bisakah Anda jelaskan apa itu Tier Layanan? Apakah lapisan terjauh dari pengguna, atau terdekat dengan pengguna?
Manoj R
Mengapa pertanyaan ini tidak sesuai pada SO?
Bjarke Freund-Hansen
@ Manoj R: Tidak juga. Lapisan atau lapisan layanan adalah tempat aturan dan logika bisnis ditetapkan, dipisahkan dari detail teknologi DB dan presentasi klien.
Michael Borgwardt
6
Pengecualian yang tidak dicentang [...] tidak muncul bahkan di Javadoc. => mereka akan muncul jika Anda mendokumentasikannya dengan @throwstag, yang merupakan praktik yang baik.
assylias
4
@ SureshKoya Java Efektif, Butir 62: Dokumentasikan semua pengecualian yang dilemparkan oleh setiap metode. Ekstrak: Gunakan @throwstag Javadoc untuk mendokumentasikan setiap pengecualian yang tidak dicentang yang dapat dilempar suatu metode, tetapi jangan gunakan kata kunci lemparan untuk memasukkan pengecualian yang tidak dicentang dalam deklarasi metode.
assylias

Jawaban:

13

Pengecualian yang dicentang adalah pengalaman gagal dalam desain bahasa. Mereka memaksa Anda untuk memiliki abstraksi yang sangat bocor dan kode kotor. Mereka harus dihindari sebisa mungkin.

Adapun poin Anda:

1) Pengecualian yang diperiksa membuat kode menjadi kotor, dan tidak kurang tidak terduga karena muncul di mana - mana .

2) Bagaimana pengecualian diperiksa ditunjukkan kepada pengguna lebih baik? Satu-satunya perbedaan nyata antara pengecualian yang diperiksa dan yang tidak dicentang adalah teknis dan hanya memengaruhi kode sumber.

3) Pernah mendengar jejak stack? Mereka memberi tahu Anda dengan tepat di mana pengecualian dilemparkan, tidak peduli apakah itu dicentang atau tidak dicentang. Sebenarnya, pengecualian yang diperiksa cenderung lebih buruk untuk debugging karena sering dibungkus yang mengarah ke jejak tumpukan yang lebih lama dan lebih buruk, atau bahkan hilang sama sekali karena pembungkusnya dilakukan dengan salah.

Ada dua jenis pengecualian: yang terjadi "normal" dan biasanya ditangani sangat dekat dengan tempat terjadinya, dan yang benar-benar luar biasa dan dapat ditangani secara umum dalam lapisan yang sangat tinggi (cukup batalkan tindakan saat ini dan catat / tampilkan kesalahan).

Pengecualian diperiksa adalah upaya untuk menempatkan perbedaan ini ke dalam sintaks bahasa pada titik pengecualian didefinisikan. Masalah dengan ini adalah

  • Perbedaannya benar-benar tergantung pada penelepon , bukan kode yang melempar pengecualian
  • Ini benar-benar ortogonal dengan makna semantik pengecualian, tetapi mengikatnya pada hierarki kelas memaksa Anda untuk mencampur keduanya.
  • Inti dari pengecualian adalah bahwa Anda dapat memutuskan pada tingkat apa untuk menangkapnya tanpa risiko kehilangan kesalahan secara diam-diam atau harus mencemari kode di tingkat menengah atau; pengecualian yang dicentang kehilangan keunggulan kedua itu.
Michael Borgwardt
sumber
1. Nah, dalam kasus pengecualian yang tidak dicentang, Anda bahkan tidak akan tahu apakah panggilan dapat mengakibatkan tidak dicentang. 2. Ketika Anda mengatakan "Ini benar-benar ortogonal dengan makna semantik dari suatu pengecualian, tetapi mengikatnya ke hierarki kelas memaksa Anda untuk mencampur keduanya", saya kira maksud Anda hierarki panggilan alih-alih hierarki kelas.
randominstanceOfLivingThing
2
@ Suresh Koya: Tidak, maksudku hirarki kelas, fakta bahwa deklarasi SQLException extends Exceptionberarti memilih untuk melempar SQLExceptionkarena kesalahan berkaitan dengan akses DB secara otomatis berarti pengecualian diperiksa. Dan Anda dapat mendokumentasikan pengecualian yang tidak dicentang dalam komentar Javadoc. Berfungsi dengan baik untuk semua bahasa lainnya.
Michael Borgwardt
1
@MichaelBorgwardt "Pengecualian yang dicentang adalah pengalaman yang gagal dalam desain bahasa", apakah itu pendapat pribadi Anda jika tidak, saya ingin membaca lebih lanjut tentang hal itu. Tautan otentik apa pun akan sangat membantu.
Vipin
2
@Vipin: Ini adalah pendapat pribadi saya, tetapi pendapat yang dibagikan oleh banyak orang, misalnya Bruce Eckel: mindview.net/Etc/Discussions/CheckedExceptions - dan fakta bahwa tidak ada bahasa lain yang mengadopsi pengecualian yang diperiksa dalam 20 tahun sejak Jawa diperkenalkan berbicara untuk dirinya sendiri ...
Michael Borgwardt
2

Pandangan saya adalah bahwa jenis pengecualian apa yang dilemparkan bergantung pada apa yang dilakukan kode Anda.

Saya melempar pengecualian yang sudah diperiksa ketika saya berharap hal itu bisa terjadi cukup sering (misalnya, pengguna memasukkan data yang cerdik) dan saya mengharapkan kode panggilan untuk menangani situasi.

Saya melempar pengecualian yang tidak dicentang / runtime (tidak sesering dicentang) ketika saya memiliki situasi langka yang tidak saya harapkan ditangani oleh kode panggilan. Contohnya mungkin semacam kesalahan terkait memori aneh yang tidak pernah saya harapkan terjadi. Tidak dicentang adalah jenis kesalahan yang Anda harapkan untuk menjatuhkan aplikasi.

Tidak terkecuali akan muncul di depan pengguna tanpa tingkat dukungan. Bahkan jika itu hanya "tolong potong dan tempel dump kesalahan ini ke email". Tidak ada yang lebih menyebalkan bagi pengguna daripada diberi tahu bahwa ada kesalahan, tetapi tidak diberi rincian atau tindakan yang dapat mereka lakukan untuk memulai perbaikan.

Dugaan saya adalah bahwa filosofi yang Anda sebutkan berasal dari salah satu dari dua sumber:

  • Pemrogram malas berusaha menghindari melakukan pekerjaan.
  • Atau pengembang yang harus mendukung kode yang sebaliknya. yaitu penanganan berlebihan kesalahan. Jenis kode yang berisi sejumlah besar penanganan pengecualian, banyak yang tidak melakukan apa-apa, atau bahkan lebih buruk, digunakan untuk kontrol aliran dan tujuan yang salah lainnya.
drekka
sumber
Jika sesuatu dapat terjadi cukup sering, itu tidak terkecuali. Tetapi setuju bahwa kesalahan tidak boleh dibuang, yang tidak diketahui pengguna.
Manoj R
Saya setuju dengan filosofi Anda. Pada aplikasi yang Anda kembangkan untuk pengguna, apa yang dibutuhkan untuk melempar pengecualian Runtime?
randominstanceOfLivingThing
Juga, Bahkan jika pengecualian Runtime dilemparkan, saya lebih suka konvensi @assylias menunjuk ke.
randominstanceOfLivingThing
1

Jika Anda tidak ingin pengecualian runtime yang tidak dicentang, lalu mengapa Anda menggunakan java? Ada kemungkinan pengecualian runtime hampir di mana-mana - terutama NullPointerException, ArithmeticException, pengecualian ArrayIndexOutOfBounds, dll.

Dan ketika Anda pernah membaca file log dari beberapa sistem J2EE, seperti, misalnya, instalasi SAP NetWeaver, Anda akan melihat bahwa pengecualian seperti itu terjadi setiap saat.

Ingo
sumber
Dari spesifikasi bahasa Java: "Kelas pengecualian runtime (RuntimeException dan subkelasnya) dikecualikan dari pengecekan waktu kompilasi karena, menurut penilaian para perancang bahasa pemrograman Java, harus menyatakan pengecualian seperti itu tidak akan membantu secara signifikan dalam membangun kebenaran. program. Banyak operasi dan konstruksi bahasa pemrograman Java dapat menghasilkan pengecualian runtime. "
randominstanceOfLivingThing
1
Pengecualian runtime yang Anda bicarakan adalah yang muncul dari Java karena sistem Java runtime tidak memiliki petunjuk mengapa Anda mencoba melakukan panggilan tertentu. Misalnya: NullPointerException akan muncul jika Anda memanggil metode yang nol. Dalam hal ini sistem runtime Java tidak memiliki kata yang tepat untuk kebodohan programmer dan akan menampar pemanggil dengan NullPointerException. Bagian yang menyedihkan adalah penelepon telah menjual produk Netweaver kepada Anda dan Anda sebagai pengguna sekarang menjadi korban pemrograman yang buruk. Para penguji juga harus disalahkan karena mereka tidak melakukan semua tes batas.
randominstanceOfLivingThing
1

Ada beberapa aturan untuk penanganan pengecualian yang harus Anda ingat. Tetapi pertama-tama, Anda harus ingat bahwa pengecualian adalah bagian dari antarmuka yang diekspos oleh kode; mendokumentasikannya . Ini terutama penting ketika antarmuka adalah antarmuka publik, tentu saja, tetapi itu adalah ide yang sangat bagus di antarmuka pribadi juga.

Pengecualian hanya harus ditangani pada titik di mana kode dapat melakukan sesuatu yang masuk akal dengannya. Opsi penanganan terburuk adalah tidak melakukan apa-apa tentang mereka, yang seharusnya hanya dilakukan ketika itu adalah pilihan yang tepat. (Ketika saya memiliki situasi seperti itu dalam kode saya, saya memasukkan komentar untuk efek itu sehingga saya tahu tidak perlu khawatir tentang tubuh kosong.)

Pilihan terburuk kedua adalah melemparkan pengecualian yang tidak terkait tanpa yang asli terlampir sebagai penyebabnya. Masalahnya di sini adalah bahwa informasi dalam pengecualian asli yang akan memungkinkan diagnosis masalah hilang; Anda sedang menciptakan sesuatu yang tak dapat melakukan apa saja dengan (selain mengeluh bahwa “itu tidak bekerja”, dan kita semua tahu bagaimana kita membenci mereka laporan bug).

Jauh lebih baik adalah mencatat pengecualian. Itu memungkinkan seseorang mengetahui apa masalahnya dan memperbaikinya, tetapi Anda hanya harus mencatat pengecualian pada titik di mana masalah tersebut akan hilang atau dilaporkan melalui koneksi eksternal. Itu bukan karena penebangan lebih sering merupakan masalah besar, tetapi karena penebangan yang berlebihan berarti Anda hanya mendapatkan lebih banyak ruang tanpa menggunakan lebih banyak informasi. Setelah Anda mencatat pengecualian, Anda dapat melaporkan suatu précis kepada pengguna / klien dengan hati nurani yang baik (selama Anda juga menyertakan waktu pembuatan - atau pengidentifikasi korelasi lainnya - dalam laporan itu sehingga versi singkatnya dapat dicocokkan. dengan detail jika perlu).

Pilihan terbaik adalah, tentu saja, untuk sepenuhnya menangani pengecualian, berurusan dengan situasi kesalahan secara keseluruhan. Jika Anda bisa melakukan ini, lakukan saja! Bahkan mungkin berarti Anda bisa menghindari harus mencatat pengecualian.

Salah satu cara untuk menangani pengecualian adalah dengan melemparkan pengecualian lain yang menyediakan deskripsi tingkat tinggi dari masalah (misalnya, " failed to initialize" bukannya " index out of bounds"). Ini adalah pola yang baik selama Anda tidak kehilangan informasi tentang penyebab pengecualian; gunakan pengecualian terperinci untuk menginisialisasi causepengecualian tingkat lebih tinggi atau catat detailnya (seperti dibahas di atas). Logging paling tepat ketika Anda akan melewati batas antar-proses, seperti panggilan IPC, karena tidak ada jaminan bahwa kelas pengecualian level rendah akan hadir sama sekali di ujung koneksi yang lain. Menjaga sebagai penyebab terlampir adalah yang paling tepat ketika melewati batas internal.

Pola lain yang Anda lihat adalah tangkapan-dan-lepas:

try {
    // ...
} catch (FooException e) {
    throw e;
}

Ini adalah anti-pola kecuali Anda memiliki batasan jenis dari catchklausa lain yang berarti Anda tidak bisa membiarkan pengecualian melewati sendiri. Maka itu hanya fitur jelek dari Java.

Tidak ada perbedaan nyata antara pengecualian yang diperiksa dan yang tidak dicentang selain fakta bahwa Anda harus menyatakan pengecualian yang diperiksa yang melintasi batas metode. Itu masih merupakan ide bagus untuk mendokumentasikan pengecualian yang tidak dicentang (dengan @throwskomentar javadoc) jika Anda tahu mereka dilemparkan dengan sengaja oleh kode Anda. Jangan dengan sengaja melempar java.lang.Erroratau subkelasnya (kecuali jika Anda sedang menulis implementasi JVM).

Opini: Kasus kesalahan tak terduga selalu mewakili bug dalam kode Anda. Pengecualian yang dicek adalah cara untuk mengelola ancaman ini, dan di mana pengembang sengaja menggunakan pengecualian yang tidak dicentang sebagai cara untuk menghindari masalah penanganan kasus kesalahan, Anda sedang membangun banyak hutang teknis yang harus Anda selesaikan beberapa waktu jika Anda ingin kode yang kuat. Penanganan kesalahan yang ceroboh tidak profesional (dan melihat penanganan kesalahan adalah cara yang baik untuk menentukan seberapa baik programmer sebenarnya).

Donal Fellows
sumber
0

Saya pikir Anda HANYA harus melempar pengecualian diperiksa ketika aplikasi dapat pulih. Jadi, pengguna perpustakaan Anda harus menangkap pengecualian itu dan melakukan apa yang perlu dipulihkan. Hal lain harus tidak dicentang.

Sebagai contoh,

Jika aplikasi Anda memuat data baik dari file atau database. Kemudian,..

try {
  File data = new File(...);
  // parse file here
} catch (Exception ex) {
  throw new MissingDataFileException("data file not found");
}

penelepon selalu dapat menangkap MissingDataFileException yang dicentang dan kemudian mencoba memuat data dari database.

try {
  Connection con = DriverManager.getConnection( host, username, password );
  // query data here
} catch (Exception ex) {
  throw new RuntimeException("better call Saul!");
}
Hendrix
sumber
1
Saulus meninggal dalam kecelakaan mobil 3 tahun yang lalu. Gagal! ;-)
Donal Fellows