Saya telah menulis sebuah fungsi yang meminta input dari pengguna sampai pengguna memasukkan bilangan bulat positif (angka alami). Seseorang berkata saya tidak boleh melempar dan menangkap pengecualian dalam fungsi saya dan harus membiarkan penelepon fungsi saya menangani mereka.
Saya ingin tahu apa yang dipikirkan pengembang lain tentang ini. Saya juga mungkin menyalahgunakan pengecualian dalam fungsi. Berikut kode di Jawa:
private static int sideInput()
{
int side = 0;
String input;
Scanner scanner = new Scanner(System.in);
do {
System.out.print("Side length: ");
input = scanner.nextLine();
try {
side = Integer.parseInt(input);
if (side <= 0) {
// probably a misuse of exceptions
throw new NumberFormatException();
}
}
catch (NumberFormatException numFormExc) {
System.out.println("Invalid input. Enter a natural number.");
}
} while (side <= 0);
return side;
}
Saya tertarik pada dua hal:
- Haruskah saya membiarkan penelepon khawatir tentang pengecualian? Maksud dari fungsi ini adalah ia mengganggu pengguna sampai pengguna memasukkan nomor alami. Apakah titik fungsi buruk? Saya tidak berbicara tentang UI (pengguna tidak bisa keluar dari loop tanpa input yang tepat), tetapi tentang input loop dengan pengecualian yang ditangani.
- Apakah Anda mengatakan bahwa pernyataan melempar (dalam hal ini) merupakan penyalahgunaan pengecualian? Saya dapat dengan mudah membuat bendera untuk memeriksa validitas nomor dan menampilkan pesan peringatan berdasarkan bendera itu. Tapi itu akan menambah lebih banyak baris ke kode dan saya pikir itu bisa dibaca apa adanya.
Masalahnya, saya sering menulis fungsi input terpisah. Jika pengguna harus memasukkan nomor beberapa kali, saya membuat fungsi terpisah untuk input yang menangani semua pengecualian dan batasan pemformatan.
exceptions
usr
sumber
sumber
Jawaban:
Inti dari pengecualian adalah memungkinkan metode untuk memberi tahu pemanggil yang memasuki kondisi yang tidak dapat dilanjutkan secara normal, tanpa memaksa Anda untuk menyematkan kode kesalahan pada nilai pengembalian.
Dalam kasus Anda, metode Anda tahu persis apa yang harus dilakukan ketika input tidak lebih besar dari 0. Satu-satunya alasan Anda menyimpan garis di sini adalah karena Anda kebetulan melempar pengecualian yang sama dengan yang akan Anda dapatkan jika inputnya bukan angka. Namun, pengecualian yang Anda lemparkan tidak mewakili dengan benar mengapa kode Anda tidak menyukai input. Jika ada orang lain yang datang dan melihat kode ini, mereka harus meluangkan waktu ekstra untuk mencoba melihat persis bagaimana semuanya berjalan.
sumber
Ini adalah penggunaan pengecualian yang buruk. Untuk mulai dengan, angka non-positif bukan pengecualian format.
Mengapa menggunakan pengecualian sama sekali? Jika Anda tahu input apa yang tidak diizinkan, jangan sampai keluar dari loop sampai Anda mendapatkan input yang valid dari pengguna, sesuatu seperti yang berikut:
sumber
Integer.parseInt()
melempar aNumberFormatException
jika tidak dapat menguraikan argumen string yang disediakan. Tidak perlu bagi Anda (dan Anda tidak akan bisa) untuk melemparkan pengecualian sendiri.Integer.parseInt()
metode ini akan melempar pengecualian untuk Anda jika itu terjadi, Anda tidak akan bisa melemparkannya sendiri setelah itu karena sudah dibuang.Hanya tangkap pengecualian jika Anda bermaksud melakukan sesuatu yang relevan dengan panggilan metode saat ini; yaitu pembersihan, kegagalan logika dll. Dalam hal ini, tangkapan hanya mengirim pesan ke konsol, itu tidak relevan dengan metode sideInput, jadi oleh karena itu dapat ditangani lebih lanjut ke rantai panggilan / tumpukan.
Seseorang dapat menyingkirkan try / catch di sini dan cukup mendokumentasikan pemanggilan metode:
Orang masih perlu menangani pengecualian itu lebih lanjut ke rantai panggilan / tumpukan!
sumber
Anda seharusnya tidak melempar dan menangkap pengecualian yang sama dalam suatu metode, saya bahkan berpikir bahwa blok tangkap akan menangkap pengecualian yang sama dengan yang Anda lempar, jadi Anda tidak benar-benar melemparkannya.
Jika
parseInt
berhasil, maka itu bukanNumberFormatException
.jika sisi kurang dari nol, Anda harus melempar
NegativeSideLengthException
;Buat Exception kustom / bisnis bernama
NegativeSideLengthException
Kemudian
sideInput
melempar NegativeSideLengthExceptionAnda bahkan dapat (jika Anda mau) menambahkan catch catch block untuk menangkap
NegativeSideLengthException
dan tidak memiliki metode melemparkannya.Bendera bukan cara yang baik untuk menangani pengecualian.
sumber
Pengecualian adalah hal yang cukup mengerikan, mereka membawa lebih banyak kompleksitas daripada yang mereka pecahkan.
Pertama, jika Anda tidak menangkap pengecualian Anda, penelepon hanya dapat melakukan
on error resume next
, yaitu, setelah satu minggu, bahkan Anda tidak akan tahu apa fungsi Anda bisa melempar, dan apa yang harus dilakukan dengan itu:Pada dasarnya, jika Anda menangkapnya, Anda harus memiliki pemahaman yang sangat baik tentang kontrak, dan jaminan pengecualian. Itu jarang terjadi di dunia nyata. Dan juga kode Anda akan sulit dibaca.
Juga, lucunya adalah bahwa jika Anda benar-benar memiliki kesempatan menangani pengecualian, Anda memerlukan bahasa RAII yang nyata, yang agak lucu, karena Java dan .NET adalah tentang pengecualian ...
Mengulangi ini sekali lagi, tetapi ...:
http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx
http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx
http://www.joelonsoftware.com/items/2003/10/13.html
sumber
: throw(thisexception, thatexception)
itu benar-benar salah dan tidak boleh digunakan, karena jika tidak, Anda akan mendapatkan pengecualian yang tidak terduga.catch
. Meskipun nilai pengembalian yang diabaikan tidak dapat ditelusuri - ini hanya dapat diidentifikasi melalui peninjauan kode baris-demi-baris. Last but not least, konstruktor tidak memiliki nilai balik, ini adalah alasan utama untuk menggunakan pengecualian.