Saya bertanya-tanya apakah saya harus mempertahankan nilai pengembalian pemanggilan metode dengan memvalidasi bahwa mereka memenuhi harapan saya, bahkan jika saya tahu bahwa metode yang saya panggil akan memenuhi harapan tersebut.
DIBERIKAN
User getUser(Int id)
{
User temp = new User(id);
temp.setName("John");
return temp;
}
HARUS SAYA LAKUKAN
void myMethod()
{
User user = getUser(1234);
System.out.println(user.getName());
}
ATAU
void myMethod()
{
User user = getUser(1234);
// Validating
Preconditions.checkNotNull(user, "User can not be null.");
Preconditions.checkNotNull(user.getName(), "User's name can not be null.");
System.out.println(user.getName());
}
Saya menanyakan hal ini pada level konseptual. Jika saya tahu cara kerja metode yang saya panggil. Entah karena saya menulisnya atau saya memeriksanya. Dan logika dari nilai yang mungkin dikembalikan memenuhi prasyarat saya. Apakah "lebih baik" atau "lebih tepat" untuk melewatkan validasi, atau haruskah saya masih mempertahankan nilai-nilai yang salah sebelum melanjutkan dengan metode yang saat ini saya laksanakan meskipun itu harus selalu berlalu.
Kesimpulan saya dari semua jawaban (jangan ragu untuk menjawab sendiri):
Tegaskan kapan- Metode ini telah menunjukkan perilaku buruk di masa lalu
- Metode ini dari sumber yang tidak dipercaya
- Metode ini digunakan dari tempat lain, dan tidak secara eksplisit menyatakan post-kondisi
- Metode ini sesuai dengan Anda (lihat jawaban yang dipilih untuk detail)
- Metode ini secara eksplisit mendefinisikan kontraknya dengan sesuatu seperti dokumen yang tepat, tipe keselamatan, uji unit, atau pemeriksaan pasca-kondisi
- Kinerja sangat penting (dalam hal ini, mode debug mode dapat digunakan sebagai pendekatan hybrid)
java
validation
null
return-type
defensive-programming
Didier A.
sumber
sumber
Null
)? Mungkin sama bermasalahnya jika namanya""
(bukan null tetapi string kosong) atau"N/A"
. Entah Anda bisa mempercayai hasilnya, atau Anda harus paranoid dengan tepat.Jawaban:
Itu tergantung pada seberapa besar kemungkinan getUser dan myMethod berubah, dan yang lebih penting, seberapa besar kemungkinan mereka berubah secara independen satu sama lain .
Jika Anda entah bagaimana tahu pasti bahwa getUser tidak akan pernah, pernah, pernah berubah di masa depan, maka ya itu buang-buang waktu untuk memvalidasinya, sama seperti membuang-buang waktu memvalidasi yang
i
memiliki nilai 3 segera setelahi = 3;
pernyataan. Pada kenyataannya, Anda tidak tahu itu. Tetapi ada beberapa hal yang Anda tahu:Apakah kedua fungsi ini "hidup bersama"? Dengan kata lain, apakah mereka memiliki orang yang sama yang memeliharanya, apakah mereka bagian dari file yang sama, dan dengan demikian apakah mereka cenderung tetap "sinkron" satu sama lain? Dalam hal ini, Anda mungkin perlu menambahkan cek validasi, karena itu hanya berarti lebih banyak kode yang harus diubah (dan berpotensi memunculkan bug) setiap kali kedua fungsi berubah atau dire-refactored ke sejumlah fungsi yang berbeda.
Apakah fungsi getUser adalah bagian dari API yang terdokumentasi dengan kontrak tertentu, dan myMethod hanya klien dari API tersebut di basis kode lain? Jika demikian, Anda dapat membaca dokumentasi itu untuk mengetahui apakah Anda harus memvalidasi nilai kembali (atau pra-memvalidasi parameter input!) Atau apakah benar-benar aman untuk mengikuti secara membabi buta jalur bahagia. Jika dokumentasi tidak memperjelas hal ini, minta pengelola untuk memperbaikinya.
Akhirnya, jika fungsi khusus ini secara tiba-tiba dan tidak terduga mengubah perilakunya di masa lalu, dengan cara yang melanggar kode Anda, Anda memiliki hak untuk menjadi paranoid tentang hal itu. Bug cenderung mengelompok.
Perhatikan bahwa semua hal di atas berlaku bahkan jika Anda adalah penulis asli dari kedua fungsi tersebut. Kami tidak tahu apakah kedua fungsi ini diharapkan untuk "hidup bersama" selama sisa hidup mereka, atau apakah mereka perlahan-lahan akan terpisah menjadi modul-modul yang terpisah, atau jika Anda entah bagaimana menembak diri Anda sendiri di kaki dengan bug yang lebih tua versi getUser. Tapi Anda mungkin bisa menebak dengan cukup baik.
sumber
getUser
nanti, sehingga bisa mengembalikan nol, akankah pemeriksaan eksplisit memberi Anda informasi yang tidak bisa Anda dapatkan dari "NullPointerException" dan nomor baris?Jawaban Ixrec baik, tetapi saya akan mengambil pendekatan yang berbeda karena saya percaya itu layak dipertimbangkan. Untuk tujuan diskusi ini saya akan berbicara tentang pernyataan, karena itulah nama yang
Preconditions.checkNotNull()
secara tradisional Anda ketahui.Yang ingin saya sarankan adalah bahwa pemrogram sering melebih-lebihkan tingkat di mana mereka yakin bahwa sesuatu akan berperilaku dengan cara tertentu, dan meremehkan konsekuensi dari tidak berperilaku seperti itu. Juga, programmer sering tidak menyadari kekuatan asersi sebagai dokumentasi. Selanjutnya, dalam pengalaman saya, programmer menegaskan hal-hal yang jauh lebih jarang daripada seharusnya.
Moto saya adalah:
Tentu saja, jika Anda benar - benar yakin bahwa sesuatu berperilaku dengan cara tertentu, Anda akan menahan diri untuk menyatakan bahwa itu memang berperilaku seperti itu, dan itu sebagian besar masuk akal. Sangat tidak mungkin untuk menulis perangkat lunak jika Anda tidak dapat mempercayai apa pun.
Tetapi ada pengecualian bahkan untuk aturan ini. Anehnya, untuk mengambil contoh Ixrec, ada semacam situasi di mana sangat diinginkan untuk mengikuti
int i = 3;
dengan pernyataan yangi
memang dalam kisaran tertentu. Ini adalah situasi di manai
kemungkinan akan diubah oleh seseorang yang mencoba berbagai skenario bagaimana-jika, dan kode yang mengikuti bergantung padai
memiliki nilai dalam rentang tertentu, dan tidak segera jelas dengan cepat melihat pada kode berikut apa kisaran yang dapat diterima adalah. Jadi,int i = 3; assert i >= 0 && i < 5;
pada awalnya mungkin tampak tidak masuk akal, tetapi jika Anda memikirkannya, ia memberi tahu Anda bahwa Anda boleh bermain dengannyai
, dan itu juga memberi tahu Anda kisaran di mana Anda harus tinggal. Pernyataan adalah jenis dokumentasi terbaik, karenaitu diberlakukan oleh mesin , jadi itu adalah jaminan yang sempurna, dan itu akan di refactored bersama-sama dengan kode , sehingga tetap relevan.getUser(int id)
Contoh Anda bukanlah kerabat konseptual yang sangat jauh dariassign-constant-and-assert-in-range
contoh tersebut. Anda tahu, secara definisi, bug terjadi ketika sesuatu menunjukkan perilaku yang berbeda dari perilaku yang kami harapkan. Benar, kami tidak bisa menegaskan semuanya, jadi terkadang ada beberapa debugging. Tapi itu adalah fakta yang sudah mapan dalam industri bahwa semakin cepat kita menemukan kesalahan, semakin sedikit biayanya. Pertanyaan yang harus Anda ajukan tidak hanya seberapa yakin Anda bahwa Anda tidakgetUser()
akan pernah mengembalikan nol, (dan tidak pernah mengembalikan pengguna dengan nama nol,) tetapi juga, hal-hal buruk apa yang akan terjadi dengan sisa kode jika tidak Bahkan suatu hari mengembalikan sesuatu yang tidak terduga, dan betapa mudahnya dengan cepat melihat sisa kode untuk mengetahui dengan tepat apa yang diharapkangetUser()
.Jika perilaku tak terduga akan menyebabkan database Anda menjadi korup, maka mungkin Anda harus menegaskan bahkan jika Anda 101% yakin itu tidak akan terjadi. Jika
null
nama pengguna akan menyebabkan beberapa kesalahan aneh yang tidak dapat dilacak, ribuan baris lebih jauh ke bawah dan milyaran siklus jam kemudian, maka mungkin yang terbaik adalah gagal sedini mungkin.Jadi, meskipun saya tidak setuju dengan jawaban Ixrec, saya menyarankan agar Anda dengan serius mempertimbangkan fakta bahwa pernyataan tidak ada biaya, jadi benar-benar tidak ada yang hilang, hanya untuk diperoleh, dengan menggunakannya secara bebas.
sumber
... && sureness < 1)
.Yang pasti tidak.
Seorang penelepon tidak boleh memeriksa apakah fungsi yang dihadapinya mematuhi kontraknya. Alasannya sederhana: ada banyak penelepon yang berpotensi dan itu tidak praktis dan bahkan bisa dibilang salah dari sudut pandang konseptual untuk setiap penelepon tunggal untuk menduplikasi logika untuk memeriksa hasil fungsi lainnya.
Jika ada pemeriksaan yang harus dilakukan, masing-masing fungsi harus memeriksa kondisi pasca sendiri. Post-conditions memberi Anda keyakinan bahwa Anda menerapkan fungsi dengan benar dan pengguna akan dapat mengandalkan kontrak fungsi Anda.
Jika fungsi tertentu tidak dimaksudkan untuk mengembalikan nol, maka ini harus didokumentasikan dan menjadi bagian dari kontrak fungsi itu. Inilah inti dari kontrak ini: menawarkan kepada pengguna beberapa invarian yang dapat mereka andalkan sehingga mereka menghadapi lebih sedikit rintangan saat menulis fungsi mereka sendiri.
sumber
Jika null adalah nilai balik yang valid dari metode getUser, maka kode Anda harus menanganinya dengan If, bukan Exception - itu bukan kasus luar biasa.
Jika null bukan nilai balik yang valid dari metode getUser, maka ada bug di getUser - metode getUser harus melempar pengecualian atau diperbaiki.
Jika metode getUser adalah bagian dari pustaka eksternal atau tidak dapat diubah dan Anda ingin pengecualian dilemparkan dalam kasus pengembalian nol, bungkus kelas dan metode untuk melakukan pemeriksaan dan melempar pengecualian sehingga setiap instance dari panggilan untuk getUser konsisten dalam kode Anda.
sumber
Saya berpendapat bahwa premis pertanyaan Anda tidak aktif: mengapa menggunakan referensi nol untuk memulai?
The Pola nol objek adalah cara untuk kembali benda-benda yang pada dasarnya melakukan apa-apa: "tidak ada pengguna" daripada kembali null untuk pengguna Anda, mengembalikan objek yang mewakili
Pengguna ini akan tidak aktif, memiliki nama kosong, dan nilai-nilai non-nol lainnya yang menunjukkan "tidak ada di sini." Manfaat utama adalah Anda tidak perlu membuang sampah sembarangan karena program Anda akan membatalkan pemeriksaan, mencatat, dll. Anda hanya menggunakan objek Anda.
Mengapa algoritma harus peduli dengan nilai nol? Langkah-langkahnya harus sama. Sangat mudah dan jauh lebih jelas untuk memiliki objek nol yang mengembalikan nol, string kosong, dll.
Berikut ini adalah contoh dari pemeriksaan kode untuk null:
Berikut adalah contoh kode menggunakan objek nol:
Mana yang lebih jelas? Saya percaya yang kedua adalah.
Sementara pertanyaan tersebut ditandai java , perlu dicatat bahwa pola objek nol benar - benar berguna dalam C ++ saat menggunakan referensi. Referensi Java lebih seperti pointer C ++, dan memungkinkan null. Referensi C ++ tidak dapat menampung
nullptr
. Jika seseorang ingin memiliki sesuatu yang analog dengan referensi nol di C ++, pola objek nol adalah satu-satunya cara yang saya tahu untuk mencapainya.sumber
getCount()
mendokumentasikan jaminan bahwa itu tidak kembali 0, dan tidak akan melakukannya di masa depan kecuali dalam keadaan di mana seseorang memutuskan untuk membuat perubahan yang melanggar dan terus memperbarui semua yang memanggilnya untuk mengatasi antarmuka baru. Melihat apa yang dilakukan kode saat ini tidak membantu, tetapi jika Anda akan memeriksa kode maka kode yang akan diperiksa adalah unit testgetCount()
. Jika mereka mengujinya untuk tidak mengembalikan 0, maka Anda tahu setiap perubahan di masa depan untuk mengembalikan 0 akan dianggap sebagai perubahan melanggar karena tes akan gagal.Secara umum, saya akan mengatakan bahwa itu terutama tergantung pada tiga aspek berikut:
kekokohan: dapatkah metode pemanggilan mengatasi
null
nilai? Jika suatunull
nilai mungkin menghasilkanRuntimeException
saya akan merekomendasikan cek - kecuali kompleksitas rendah dan metode yang dipanggil / dipanggil dibuat oleh penulis yang sama, dannull
tidak diharapkan (misalnya keduanyaprivate
dalam paket yang sama).tanggung jawab kode: jika pengembang A bertanggung jawab untuk
getUser()
metode ini, dan pengembang B menggunakannya (misalnya sebagai bagian dari perpustakaan), saya sangat merekomendasikan untuk memvalidasi nilainya. Hanya karena pengembang B mungkin tidak tahu tentang perubahan yang menghasilkannull
nilai pengembalian potensial .kompleksitas: semakin tinggi kompleksitas keseluruhan dari program atau lingkungan, semakin saya akan merekomendasikan untuk memvalidasi nilai kembali. Bahkan jika Anda merasa yakin bahwa hari ini tidak mungkin
null
dalam konteks metode pemanggilan, mungkin Anda harus mengubahgetUser()
kasus penggunaan lain. Setelah beberapa bulan atau tahun berlalu, dan ribuan baris kode telah ditambahkan, ini bisa menjadi jebakan.Selain itu, saya akan merekomendasikan untuk mendokumentasikan
null
nilai pengembalian potensial dalam komentar JavaDoc. Karena menyoroti deskripsi JavaDoc di sebagian besar IDE, ini bisa menjadi peringatan bermanfaat bagi siapa pun yang menggunakangetUser()
.sumber
Anda tentu tidak perlu.
Misalnya, jika Anda sudah tahu bahwa pengembalian tidak akan pernah menjadi nol - Mengapa Anda ingin menambahkan cek nol? Menambahkan cek nol tidak akan merusak apa pun tetapi itu hanya berlebihan. Dan lebih baik tidak kode logika yang berlebihan selama Anda bisa menghindarinya.
sumber