Saya sedang membangun API, fungsi yang mengunggah file. Fungsi ini tidak akan mengembalikan apa-apa / batal jika file diunggah dengan benar dan memberikan pengecualian ketika ada masalah.
Mengapa pengecualian dan bukan hanya salah? Karena di dalam pengecualian saya dapat menentukan alasan kegagalan (tidak ada koneksi, nama file hilang, kata sandi salah, deskripsi file hilang, dll). Saya ingin membuat pengecualian khusus (dengan beberapa enum untuk membantu pengguna API untuk menangani semua kesalahan).
Apakah ini praktik yang baik atau lebih baik mengembalikan objek (dengan boolean di dalamnya, pesan kesalahan opsional dan enum untuk kesalahan)?
java
api-design
exceptions
functions
architectural-patterns
Accollativo
sumber
sumber
Result<T, E>
manaT
hasilnya jika berhasil danE
kesalahan jika tidak berhasil. Melempar pengecualian (bisa - tidak begitu yakin di Jawa) bisa mahal karena melibatkan melepas tumpukan panggilan, tetapi membuat objek Pengecualian itu murah. Jelas, tetap berpegang pada pola bahasa yang Anda gunakan, tetapi jangan menggabungkan boolean dan pengecualian seperti ini.fillInStackTrace();
disebut dalam konstruktor super, di kelasThrowable
Jawaban:
Melempar pengecualian hanyalah cara tambahan untuk membuat metode mengembalikan nilai. Penelepon dapat memeriksa nilai kembali semudah menangkap pengecualian dan memeriksanya. Karena itu, memutuskan antara
throw
danreturn
membutuhkan kriteria lain.Melempar pengecualian harus sering dihindari jika membahayakan efisiensi program Anda (membangun objek pengecualian dan melepaskan tumpukan panggilan jauh lebih berfungsi untuk komputer daripada hanya mendorong nilai ke dalamnya). Tetapi jika tujuan metode Anda adalah untuk mengunggah file, maka bottleneck akan selalu menjadi jaringan dan sistem file I / O, jadi tidak ada gunanya untuk mengoptimalkan metode pengembalian.
Itu juga ide yang buruk untuk membuang pengecualian untuk apa yang seharusnya menjadi aliran kontrol sederhana (misalnya ketika pencarian berhasil dengan menemukan nilainya), karena itu melanggar harapan pengguna API. Tetapi metode gagal memenuhi tujuannya adalah kasus luar biasa (atau setidaknya seharusnya), jadi saya tidak melihat alasan untuk tidak melempar pengecualian. Dan jika Anda melakukan itu, Anda bisa menjadikannya pengecualian khusus, lebih informatif (tapi itu ide yang baik untuk membuatnya menjadi subkelas standar, seperti pengecualian yang lebih umum seperti
IOException
).sumber
Sama sekali tidak ada alasan untuk kembali
true
sukses jika Anda tidak kembalifalse
pada kegagalan. Seperti apa seharusnya kode klien?Dalam hal ini, penelepon membutuhkan blok coba-tangkap, tetapi kemudian ia dapat menulis:
Jadi nilai
true
kembali sama sekali tidak relevan untuk penelepon. Jadi simpan saja metodenyavoid
.Secara umum, ada tiga cara untuk merancang mode failre.
void
, lempar (dicentang) pengecualianKembali
true
/false
Ini digunakan di beberapa API yang lebih tua, kebanyakan c-style. Kerugiannya adalah obviuos, Anda tidak tahu apa yang salah. PHP cukup sering melakukan ini, mengarah ke kode seperti ini:
Dalam konteks multi-utas, ini bahkan lebih buruk.
Melempar (dicentang) pengecualian
Ini cara yang bagus untuk melakukannya. Di beberapa titik, Anda dapat mengharapkan kegagalan. Java melakukan ini dengan soket. Asumsi dasarnya adalah bahwa panggilan harus berhasil, tetapi semua orang tahu bahwa operasi tertentu mungkin gagal. Koneksi soket ada di antara mereka. Jadi penelepon terpaksa menangani kegagalan. itu desain yang bagus, karena memastikan penelepon benar-benar menangani kegagalan, dan memberi penelepon cara yang elegan untuk menangani kegagalan.
Kembalikan objek hasil
Ini adalah cara lain yang bagus untuk menangani ini. Ini sering digunakan untuk parsing atau hanya hal-hal yang perlu divalidasi.
Bagus, logika bersih untuk penelepon juga.
Ada sedikit perdebatan kapan harus menggunakan kasus kedua, dan kapan harus menggunakan yang ketiga. Beberapa orang percaya bahwa pengecualian harus luar biasa dan bahwa Anda tidak boleh merancang dengan kemungkinan pengecualian dalam pikiran, dan akan selalu menggunakan opsi ketiga. Tidak masalah. Tetapi kami telah memeriksa pengecualian di Jawa, jadi saya tidak melihat alasan untuk tidak menggunakannya. Saya menggunakan ekspektasi yang dicentang ketika asumsi dasarnya adalah bahwa panggilan harus berhasil (seperti menggunakan soket), tetapi kegagalan mungkin terjadi, dan saya menggunakan opsi ketiga ketika sangat tidak jelas apakah panggilan tersebut akan berhasil (seperti memvalidasi data). Tetapi ada pendapat berbeda tentang ini.
Dalam kasus Anda, saya akan menggunakan
void
+Exception
. Anda mengharapkan unggahan file berhasil, dan ketika tidak, itu luar biasa. Tetapi penelepon dipaksa untuk menangani mode kegagalan itu, dan Anda dapat mengembalikan Pengecualian yang dengan benar menjelaskan kesalahan apa yang terjadi.sumber
Ini benar-benar bermuara pada apakah kegagalan itu luar biasa atau diharapkan .
Jika kesalahan bukan sesuatu yang Anda harapkan secara umum, maka kemungkinan besar pengguna API akan memanggil metode Anda tanpa penanganan kesalahan khusus. Melempar pengecualian memungkinkan untuk menggelembungkan tumpukan ke tempat di mana ia diperhatikan.
Jika di sisi lain kesalahan adalah hal biasa, Anda harus mengoptimalkan untuk pengembang yang memeriksa mereka, dan
try-catch
klausa sedikit lebih rumit daripada seriif/elif
atauswitch
.Selalu desain API dalam pola pikir seseorang yang menggunakannya.
sumber
Jangan mengembalikan boolean jika Anda tidak pernah ingin kembali
false
. Cukup buat metodevoid
dan dokumentasikan bahwa ia akan melempar pengecualian (IOException
cocok) pada kegagalan.Alasan untuk ini adalah bahwa jika Anda mengembalikan boolean, pengguna API Anda dapat menyimpulkan bahwa ia dapat melakukan ini:
Tentu saja itu tidak akan berhasil; yaitu, ada ketidaksesuaian antara kontrak metode Anda dan perilakunya. Jika Anda melemparkan pengecualian yang dicentang, pengguna metode ini harus menangani kegagalan:
sumber
Jika metode Anda memiliki nilai balik, melemparkan pengecualian mungkin mengejutkan penggunanya. Jika saya melihat metode mengembalikan boolean, saya cukup yakin itu akan mengembalikan true jika berhasil dan salah jika tidak, dan saya akan menyusun kode saya menggunakan klausa if-else. Jika pengecualian Anda akan didasarkan pada enum, Anda mungkin juga mengembalikan nilai enum, mirip dengan windows HResult, dan menyimpan nilai enum untuk saat metode berhasil.
Ini juga menjengkelkan untuk memiliki pengecualian metode melempar ketika itu bukan langkah terakhir dalam suatu prosedur. Harus menulis aliran coba-tangkap dan alihkan kendali ke blok tangkap adalah resep yang baik untuk spageti, dan harus dihindari.
Jika Anda maju dengan pengecualian, coba kembalikan void sebagai gantinya, pengguna akan mengira itu berhasil jika tidak ada pengecualian yang dilemparkan, dan tidak ada yang akan mencoba menggunakan klausa if-else untuk mengalihkan aliran kontrol.
sumber