Saya punya metode yang seharusnya mengembalikan objek jika ditemukan.
Jika tidak ditemukan, haruskah saya:
- kembali nol
- lempar pengecualian
- lain
Saya punya metode yang seharusnya mengembalikan objek jika ditemukan.
Jika tidak ditemukan, haruskah saya:
Jawaban:
Jika Anda selalu berharap untuk menemukan nilai, maka lempar pengecualian jika nilai itu hilang. Pengecualian akan berarti bahwa ada masalah.
Jika nilainya dapat hilang atau ada dan keduanya valid untuk logika aplikasi, maka kembalikan nol.
Lebih penting: Apa yang Anda lakukan di tempat lain dalam kode? Konsistensi penting.
GetPersonById(25)
akan melempar jika orang itu telah dihapus, tetapi GetPeopleByHairColor("red")
akan mengembalikan hasil kosong. Jadi, saya pikir parameter mengatakan sesuatu tentang harapan.
Hanya melempar pengecualian jika ini benar-benar kesalahan. Jika perilaku yang diharapkan untuk objek tidak ada, kembalikan null.
Kalau tidak, itu adalah masalah preferensi.
Sebagai aturan umum, jika metode harus selalu mengembalikan objek, maka pergi dengan pengecualian. Jika Anda mengantisipasi null sesekali dan ingin menanganinya dengan cara tertentu, ikuti nol tersebut.
Apa pun yang Anda lakukan, saya sangat menyarankan terhadap opsi ketiga: Mengembalikan string yang mengatakan "WTF".
Jika nol tidak pernah menunjukkan kesalahan maka kembalilah nol.
Jika nol selalu merupakan kesalahan maka lemparkan pengecualian.
Jika nol terkadang merupakan pengecualian maka kode dua rutinitas. Satu rutin melempar pengecualian dan yang lainnya adalah rutin uji boolean yang mengembalikan objek dalam parameter output dan rutin mengembalikan false jika objek tidak ditemukan.
Sulit untuk menyalahgunakan rutinitas Coba. Sangat mudah untuk lupa untuk memeriksa null.
Jadi ketika nol adalah kesalahan yang baru saja Anda tulis
object o = FindObject();
Ketika nol bukan kesalahan, Anda bisa mengkodekan sesuatu seperti
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
dan findOrFail
dari Laravel
TryFindObject
metode ini? Tuples tampaknya lebih merupakan paradigma malas untuk programmer yang tidak ingin meluangkan waktu untuk mendefinisikan objek yang merangkum beberapa nilai. Itu pada dasarnya semua tuple pada intinya lagian.
Saya hanya ingin merekapitulasi opsi yang disebutkan sebelumnya, memasukkan beberapa opsi baru ke:
Atau Anda dapat menggabungkan opsi ini:
Berikan beberapa versi rajin Anda yang rajin, sehingga penelepon dapat memutuskan ke mana harus pergi. Dalam kebanyakan kasus, hanya yang pertama memiliki implementasi algoritma pencarian, dan yang lainnya hanya membungkus yang pertama:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Bahkan jika Anda memilih untuk menyediakan hanya satu implementasi, Anda mungkin ingin menggunakan konvensi penamaan seperti itu untuk memperjelas kontrak Anda, dan itu membantu Anda jika Anda pernah memutuskan untuk menambahkan implementasi lain juga.
Anda tidak boleh menggunakannya secara berlebihan, tetapi mungkin bermanfaat, terutama ketika menulis Kelas pembantu yang akan Anda gunakan dalam ratusan aplikasi yang berbeda dengan banyak konvensi penanganan kesalahan yang berbeda.
Expected<T> findObject(String)
mana Expected<T>
memiliki fungsi orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Ini abstrak pengambilan data dari penanganan kesalahan
Gunakan pola objek nol atau lempar pengecualian.
Person somePerson = personRepository.find("does-not-exist");
Mari kita asumsikan metode ini mengembalikan objek null untuk ID does-not-exist
. Untuk apa perilaku yang benar somePerson.getAge()
? Saat ini, saya belum yakin pola objek nol adalah solusi yang tepat untuk pencarian entitas.
Keuntungan melempar pengecualian:
Untuk penjelasan lebih lanjut dengan contoh, lihat: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
itu tergantung apakah bahasa dan kode Anda dipromosikan: LBYL (lihat sebelum Anda melompat) atau EAFP (lebih mudah untuk meminta maaf daripada izin)
LBYL mengatakan Anda harus memeriksa nilai-nilai (jadi kembalikan nol)
EAFP mengatakan untuk hanya mencoba operasi dan melihat apakah gagal (membuang pengecualian)
meskipun saya setuju dengan di atas .. pengecualian harus digunakan untuk kondisi luar biasa / kesalahan, dan mengembalikan nol adalah yang terbaik saat menggunakan cek.
EAFP vs. LBYL dalam Python:
http://mail.python.org/pipermail/python-list/2003-May/2051818.html
( Arsip Web )
Tanyakan kepada diri sendiri: "apakah ini merupakan kasus luar biasa bahwa objek tidak ditemukan"? Jika diharapkan terjadi dalam program normal program Anda, Anda mungkin tidak boleh mengajukan pengecualian (karena itu bukan perilaku yang luar biasa).
Versi singkat: gunakan pengecualian untuk menangani perilaku luar biasa, bukan untuk menangani aliran kontrol normal dalam program Anda.
-Alan.
Pengecualian terkait dengan Desain berdasarkan Kontrak.
Antarmuka suatu objek sebenarnya merupakan kontrak antara dua objek, pemanggil harus memenuhi kontrak atau penerima mungkin saja gagal dengan pengecualian. Ada dua kontrak yang mungkin
1) semua input metode ini valid, dalam hal ini Anda harus mengembalikan nol ketika objek tidak ditemukan.
2) hanya beberapa input yang valid, yaitu yang menghasilkan objek yang ditemukan. Dalam hal ini Anda HARUS menawarkan metode kedua yang memungkinkan penelepon untuk menentukan apakah inputnya akan benar. Sebagai contoh
is_present(key)
find(key) throws Exception
JIKA dan HANYA JIKA Anda memberikan kedua metode kontrak ke-2, Anda diizinkan untuk melemparkan pengecualian tidak ada yang ditemukan!
Saya lebih suka mengembalikan nol, dan mengandalkan penelepon untuk menanganinya dengan tepat. Pengecualian (karena tidak ada kata yang lebih baik) adalah jika saya benar-benar 'yakin' metode ini akan mengembalikan objek. Dalam hal itu kegagalan adalah hal yang harus dan harus dilemparkan.
Bergantung pada apa artinya benda itu tidak ditemukan.
Jika keadaan normal, maka kembalikan nol. Ini hanya sesuatu yang mungkin terjadi sesekali, dan penelepon harus memeriksanya.
Jika itu adalah kesalahan, lalu melempar pengecualian, penelepon harus memutuskan apa yang harus dilakukan dengan kondisi kesalahan objek yang hilang.
Pada akhirnya keduanya akan berfungsi, meskipun kebanyakan orang umumnya menganggap itu praktik yang baik untuk hanya menggunakan Pengecualian ketika sesuatu, yah, Luar Biasa telah terjadi.
Berikut beberapa saran lagi.
Jika mengembalikan koleksi, hindari pengembalian nol, kembalikan koleksi kosong yang membuat penghitungan lebih mudah untuk ditangani tanpa cek nol terlebih dahulu.
Beberapa .NET API menggunakan pola parameter thrownOnError yang memberikan pemanggil pilihan apakah itu benar-benar situasi yang luar biasa atau tidak jika objek tidak ditemukan. Type.GetType adalah contoh dari ini. Pola umum lainnya dengan BCL adalah pola TryGet di mana boolean dikembalikan dan nilai dilewatkan melalui parameter output.
Anda juga bisa mempertimbangkan pola Objek Null dalam beberapa keadaan yang bisa menjadi default atau versi tanpa perilaku. Kuncinya adalah menghindari cek nol di seluruh basis kode. Lihat di sini untuk informasi lebih lanjut http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
Dalam beberapa fungsi saya menambahkan parameter:
..., bool verify = true)
Benar berarti melempar, salah berarti mengembalikan beberapa nilai pengembalian kesalahan. Dengan cara ini, siapa pun yang menggunakan fungsi ini memiliki kedua opsi. Defaultnya harus benar, untuk kepentingan mereka yang lupa tentang penanganan kesalahan.
Kembalikan nol alih-alih melempar pengecualian dan jelas mendokumentasikan kemungkinan nilai pengembalian nol dalam dokumentasi API. Jika kode panggilan tidak menghormati API dan memeriksa kasus nol, kemungkinan besar akan menghasilkan semacam "pengecualian penunjuk nol" pula :)
Dalam C ++, saya dapat memikirkan 3 rasa berbeda dalam mengatur metode yang menemukan objek.
Opsi A
Object *findObject(Key &key);
Kembalikan nol ketika suatu objek tidak dapat ditemukan. Bagus dan sederhana. Saya akan memilih yang ini. Pendekatan alternatif di bawah ini adalah untuk orang-orang yang tidak membenci out-params.
Opsi B
void findObject(Key &key, Object &found);
Berikan referensi ke variabel yang akan menerima objek. Metode ini membuat pengecualian ketika suatu objek tidak dapat ditemukan. Konvensi ini mungkin lebih cocok jika itu tidak benar-benar diharapkan untuk suatu objek tidak ditemukan - maka Anda melemparkan pengecualian untuk menandakan bahwa itu adalah kasus yang tidak terduga.
Opsi C
bool findObject(Key &key, Object &found);
Metode mengembalikan false ketika suatu objek tidak dapat ditemukan. Keuntungan opsi over ini A adalah Anda dapat memeriksa kasus kesalahan dalam satu langkah yang jelas:
if (!findObject(myKey, myObj)) { ...
hanya merujuk pada kasus di mana null tidak dianggap sebagai perilaku luar biasa saya pasti untuk metode coba, jelas, tidak perlu "membaca buku" atau "melihat sebelum Anda melompat" seperti yang dikatakan di sini
pada dasarnya:
bool TryFindObject(RequestParam request, out ResponseParam response)
dan ini berarti bahwa kode pengguna juga akan jelas
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Jika penting untuk kode klien untuk mengetahui perbedaan antara ditemukan dan tidak ditemukan dan ini seharusnya menjadi perilaku rutin, maka yang terbaik adalah mengembalikan nol. Kode klien kemudian dapat memutuskan apa yang harus dilakukan.
Secara umum itu harus mengembalikan nol. Kode yang memanggil metode harus memutuskan apakah akan melempar pengecualian atau mencoba sesuatu yang lain.
Atau kembalikan Opsi
Opsi pada dasarnya adalah kelas kontainer yang memaksa klien untuk menangani kasing. Scala memiliki konsep ini, lihat API-nya.
Kemudian Anda memiliki metode seperti T getOrElse (T valueIfNull) pada objek ini yang dapat mengembalikan objek yang ditemukan, atau allternative yang ditentukan klien.
Sayangnya JDK tidak konsisten, jika Anda mencoba mengakses kunci yang tidak ada dalam bundel sumber daya, Anda tidak menemukan pengecualian dan ketika Anda meminta nilai dari peta Anda mendapatkan nol jika itu tidak ada. Jadi saya akan mengubah jawaban pemenang menjadi yang berikut, jika nilai yang ditemukan bisa nol, maka naikkan pengecualian ketika tidak ditemukan, jika tidak kembalikan nol. Jadi ikuti aturan dengan satu pengecualian, jika Anda perlu tahu mengapa nilai tidak ditemukan maka selalu naikkan pengecualian, atau ..
Selama itu seharusnya mengembalikan referensi ke objek, mengembalikan NULL harus baik.
Namun, jika itu mengembalikan seluruh hal yang berdarah (seperti di C ++ jika Anda melakukannya: 'return bla;' daripada 'return & bla;' (atau 'bla' adalah pointer), maka Anda tidak dapat mengembalikan NULL, karena itu bukan tipe 'objek'. Dalam hal itu, melemparkan pengecualian, atau mengembalikan objek kosong yang tidak memiliki kumpulan flag sukses adalah bagaimana saya akan mendekati masalah.
Jangan berpikir ada orang yang menyebutkan overhead dalam penanganan pengecualian - membutuhkan sumber daya tambahan untuk memuat dan memproses pengecualian sehingga kecuali itu adalah aplikasi yang benar-benar membunuh atau memproses acara berhenti (maju akan menyebabkan lebih banyak kerugian daripada kebaikan) Saya akan memilih untuk melewatkan kembali nilai lingkungan panggilan bisa menafsirkan sesuai keinginan.
Saya setuju dengan apa yang tampaknya menjadi konsensus di sini (mengembalikan nol jika "tidak ditemukan" adalah hasil yang normal, atau melemparkan pengecualian jika semantik situasi mengharuskan objek selalu ditemukan).
Namun, ada kemungkinan ketiga yang mungkin masuk akal tergantung pada situasi khusus Anda. Metode Anda dapat mengembalikan objek default dalam kondisi "tidak ditemukan", yang memungkinkan kode panggilan diyakinkan bahwa ia akan selalu menerima objek yang valid tanpa perlu pengecekan nol atau penangkapan pengecualian.
Pengecualian harus luar biasa . Kembalikan null jika valid untuk mengembalikan nol .
Jika metode mengembalikan koleksi, lalu mengembalikan koleksi kosong (seperti dikatakan di atas). Tapi tolong jangan Collections.EMPTY_LIST atau semacamnya! (dalam hal Jawa)
Jika metode ini mengambil satu objek, maka Anda memiliki beberapa opsi.
Hati-hati, jika Anda memutuskan untuk mengembalikan nol. Jika Anda bukan satu-satunya programmer dalam proyek, Anda akan mendapatkan NullPointerExceptions (di Jawa atau apa pun dalam Bahasa lain) saat dijalankan! Jadi jangan mengembalikan nol yang tidak dicentang pada waktu kompilasi.
null
. Lihat jawaban terpilih untuk lebih banyak.
Jika Anda menggunakan perpustakaan atau kelas lain yang melempar pengecualian, Anda harus memikirkannya kembali. Berikut ini sebuah contoh. Example2.java seperti perpustakaan dan Example.java menggunakan objek itu. Main.java adalah contoh untuk menangani Pengecualian ini. Anda harus menunjukkan pesan yang bermakna dan (jika perlu) menumpuk jejak ke pengguna di sisi panggilan.
Main.java
public class Main {
public static void main(String[] args) {
Example example = new Example();
try {
Example2 obj = example.doExample();
if(obj == null){
System.out.println("Hey object is null!");
}
} catch (Exception e) {
System.out.println("Congratulations, you caught the exception!");
System.out.println("Here is stack trace:");
e.printStackTrace();
}
}
}
Contoh.java
/**
* Example.java
* @author Seval
* @date 10/22/2014
*/
public class Example {
/**
* Returns Example2 object
* If there is no Example2 object, throws exception
*
* @return obj Example2
* @throws Exception
*/
public Example2 doExample() throws Exception {
try {
// Get the object
Example2 obj = new Example2();
return obj;
} catch (Exception e) {
// Log the exception and rethrow
// Log.logException(e);
throw e;
}
}
}
Example2.java
/**
* Example2.java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
Itu sangat tergantung pada apakah Anda berharap untuk menemukan objek, atau tidak. Jika Anda mengikuti aliran pemikiran bahwa pengecualian harus digunakan untuk menunjukkan sesuatu, well, err, pengecualian telah terjadi kemudian:
Jika tidak, kembalikan nol.