Saya memiliki beberapa kode yang gagal karena NullPointerException. Suatu metode dipanggil pada objek yang objeknya tidak ada.
Namun, ini membuat saya berpikir tentang cara terbaik untuk memperbaikinya. Apakah saya selalu kode untuk nulls defensif sehingga saya kode bukti masa depan untuk pengecualian null pointer, atau haruskah saya memperbaiki penyebab nol sehingga tidak akan terjadi hilir.
Apa yang kamu pikirkan?
Jawaban:
Jika nol adalah parameter input yang masuk akal untuk metode Anda, perbaiki metode tersebut. Jika tidak, perbaiki pemanggil. "Masuk akal" adalah istilah yang fleksibel, jadi saya mengusulkan tes berikut: Bagaimana metode ini harus memberikan input nol? Jika Anda menemukan lebih dari satu jawaban yang mungkin, maka nol bukanlah input yang masuk akal.
sumber
Precondition.checkNotNull(...)
. Lihat stackoverflow.com/questions/3022319/…IllegalArgumentException
ketika diberikan nol. Ini memberi sinyal kepada penelepon tentang metode bahwa bug ada dalam kode mereka (bukan dalam metode itu sendiri).Jangan gunakan null, gunakan Opsional
Seperti yang telah Anda tunjukkan, salah satu masalah terbesar
null
di Jawa adalah dapat digunakan di mana saja , atau setidaknya untuk semua jenis referensi.Tidak mungkin mengatakan itu bisa
null
dan apa yang tidak bisa.Java 8 memperkenalkan pola yang lebih baik banyak:
Optional
.Dan contoh dari Oracle:
Jika masing-masing dari ini dapat atau tidak dapat mengembalikan nilai yang berhasil, Anda dapat mengubah API ke
Optional
s:Dengan secara eksplisit menyandikan opsionalitas dalam tipe, antarmuka Anda akan jauh lebih baik, dan kode Anda akan lebih bersih.
Jika Anda tidak menggunakan Java 8, Anda dapat melihatnya
com.google.common.base.Optional
di Google Guava.Penjelasan yang baik oleh tim Guava: https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
Penjelasan yang lebih umum tentang kerugian hingga nol, dengan contoh-contoh dari beberapa bahasa: https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/
@Nullull, @Nullable
Java 8 menambahkan anotasi ini untuk membantu alat pengecekan kode seperti IDE menangkap masalah. Mereka cukup terbatas dalam efektivitasnya.
Periksa kapan masuk akal
Jangan menulis 50% dari kode Anda memeriksa nol, terutama jika tidak ada yang masuk akal kode Anda dapat dilakukan dengan
null
nilai.Di sisi lain, jika
null
bisa digunakan dan berarti sesuatu, pastikan untuk menggunakannya.Pada akhirnya, Anda jelas tidak dapat menghapus
null
dari Jawa. Saya sangat menyarankan untuk menggantiOptional
abstraksi jika memungkinkan, dan memeriksanull
waktu lain yang Anda bisa lakukan sesuatu yang masuk akal tentangnya.sumber
NullPointerException
? ANullPointerException
dapat terjadi secara harfiah setiap kali Anda memanggil metode instance di Java. Anda akan memilikithrows NullPointerException
hampir di setiap metode tunggal.Ada beberapa cara untuk menangani ini, membumbui kode Anda dengan
if (obj != null) {}
tidak ideal, berantakan, menambah kebisingan ketika membaca kode nanti selama siklus pemeliharaan dan rentan kesalahan, karena mudah untuk lupa melakukan pembungkus pelat ketel ini.Itu tergantung pada apakah Anda ingin kode untuk melanjutkan eksekusi diam-diam atau gagal. Apakah
null
ada kesalahan atau kondisi yang diharapkan.Apa itu null?
Dalam setiap definisi dan kasus, Null mewakili kurangnya data. Nulls dalam database mewakili kurangnya nilai untuk kolom itu. nol
String
tidak sama dengan kosongString
, nolint
tidak sama dengan NOL, secara teori. Dalam prakteknya "itu tergantung". KosongString
dapat membuatNull Object
implementasi yang baik untuk kelas String, karenaInteger
itu tergantung pada logika bisnis.Alternatifnya adalah:
The
Null Object
pola. Buat instance objek Anda yang mewakilinull
negara, dan inisialisasi semua referensi untuk jenis itu dengan referensi untukNull
implementasi. Ini berguna untuk objek tipe nilai sederhana yang tidak memiliki banyak referensi ke objek lain yang juga bisanull
dan diharapkannull
sebagai keadaan yang valid.Gunakan alat Berorientasi Aspek untuk menenun metode dengan
Null Checker
aspek yang mencegah parameter menjadi nol. Ini untuk kasus di mananull
ada kesalahan.Gunakan
assert()
tidak jauh lebih baik daripadaif (obj != null){}
tetapi lebih sedikit noise.Gunakan alat Penegakan Kontrak seperti Kontrak Untuk Jawa . Kasus penggunaan yang sama dengan sesuatu seperti AspectJ tetapi lebih baru dan menggunakan Anotasi alih-alih file konfigurasi eksternal. Terbaik dari kedua karya Aspects dan Asserts.
1 adalah solusi ideal ketika data yang masuk diketahui
null
dan perlu diganti dengan beberapa nilai default sehingga konsumen hulu tidak perlu berurusan dengan semua kode boilerplate null checking. Memeriksa nilai-nilai default yang diketahui akan lebih ekspresif juga.2, 3, dan 4 hanyalah generator Exception alternatif yang nyaman untuk diganti
NullPointerException
dengan sesuatu yang lebih informatif, yang selalu dan perbaikan.Pada akhirnya
null
di Jawa hampir selalu merupakan kesalahan logika. Anda harus selalu berusaha menghilangkan akar penyebabNullPointerExceptions
. Anda harus berusaha untuk tidak menggunakannull
kondisi sebagai logika bisnis.if (x == null) { i = someDefault; }
buat saja assigment awal ke instance objek default itu.sumber
null
tidak terduga maka itu adalah kesalahan sejati, maka semuanya akan berhenti total.null == null
(bahkan dalam PHP), tetapi dalam Database,null != null
karena dalam database itu mewakili nilai yang tidak diketahui daripada "tidak ada". Dua yang tidak diketahui tidak harus sama, sedangkan dua tidak sama.Menambahkan cek nol dapat membuat pengujian bermasalah. Lihat kuliah hebat ini ...
Lihat kuliah ceramah Google Tech: "Pembicaraan Kode Bersih - Jangan Mencari Hal-Hal!" dia membicarakannya sekitar menit 24
http://www.youtube.com/watch?v=RlfLCWKxHJ0&list=PL693EFD059797C21E
Pemrograman paranoid melibatkan menambahkan cek nol di mana-mana. Sepertinya ide yang baik pada awalnya namun dari perspektif pengujian, itu membuat pengujian jenis cek nol Anda sulit untuk dihadapi.
Juga, ketika Anda membuat prasyarat untuk keberadaan beberapa objek seperti
itu mencegah Anda membuat House karena Anda akan melemparkan pengecualian. Anggap kasus pengujian Anda membuat benda tiruan untuk menguji sesuatu selain Door, yah, Anda tidak dapat melakukan ini karena pintu diperlukan
Mereka yang telah menderita melalui neraka penciptaan Mock sangat menyadari jenis gangguan ini.
Singkatnya, rangkaian uji Anda harus cukup kuat untuk menguji Pintu, Rumah, Atap atau apa pun tanpa harus paranoid karenanya. Seroiusly, betapa sulitnya menambahkan tes cek nol untuk objek tertentu dalam pengujian Anda :)
Anda harus selalu lebih suka aplikasi yang berfungsi karena Anda memiliki beberapa tes yang MEMBUKTIKAN kerjanya, daripada BERHARAP berfungsi hanya karena Anda memiliki sejumlah besar cek nol prasyarat di semua tempat
sumber
tl; dr - BAIK untuk memeriksa hal-hal yang tidak terduga
null
tetapi BURUK untuk suatu aplikasi untuk mencoba menjadikannya baik.Detail
Jelas, ada situasi di mana
null
input atau output yang valid untuk suatu metode, dan yang lain di mana tidak.Aturan # 1:
Aturan # 2:
Dengan spesifikasi yang jelas dari "kontrak" metode vis-a-vis
null
, ini merupakan kesalahan pemrograman untuk melewatkan atau mengembalikannull
tempat yang seharusnya tidak Anda miliki.Aturan # 3:
Jika suatu metode mendeteksi suatu
null
yang seharusnya tidak ada di sana, itu seharusnya tidak berusaha untuk memperbaiki masalah dengan mengubahnya menjadi sesuatu yang lain. Itu hanya menyembunyikan masalah dari programmer. Sebagai gantinya, ini harus memungkinkan NPE terjadi, dan menyebabkan kegagalan sehingga programmer dapat mengetahui apa penyebab root dan memperbaikinya. Semoga kegagalan akan diperhatikan selama pengujian. Jika tidak, itu berarti sesuatu tentang metodologi pengujian Anda.Aturan # 4:
Jika Anda memiliki bug dalam kode Anda yang menghasilkan banyak NPE, hal yang paling sulit adalah mencari tahu dari mana
null
nilai - nilai itu berasal. Salah satu cara untuk membuat diagnosis lebih mudah adalah dengan menulis kode Anda sehingganull
terdeteksi sesegera mungkin. Seringkali Anda dapat melakukan ini bersamaan dengan cek lainnya; misalnya(Jelas ada kasus di mana aturan 3 dan 4 harus diimbangi dengan kenyataan. Misalnya (aturan 3), beberapa jenis aplikasi harus berusaha untuk melanjutkan setelah mendeteksi kemungkinan kesalahan pemrograman. Dan (aturan 4) terlalu banyak memeriksa parameter buruk dapat memiliki dampak kinerja.)
sumber
Saya akan merekomendasikan memperbaiki metode menjadi defensif. Contohnya:
Harus lebih seperti ini:
Saya menyadari ini benar-benar sepele, tetapi jika penyerang mengharapkan suatu objek memberi mereka objek default yang tidak akan menyebabkan nol untuk diteruskan.
sumber
new String()
sama sekali.null
s secara diam-diam adalah opsi yang paling buruk, lebih buruk daripada melempar NPE.Aturan umum berikut tentang null telah banyak membantu saya sejauh ini:
Jika data berasal dari luar kendali Anda, periksa secara sistematis nol dan bertindak dengan tepat. Ini berarti melempar pengecualian yang masuk akal ke fungsi (dicentang atau tidak dicentang, pastikan nama pengecualian memberi tahu Anda dengan tepat apa yang sedang terjadi.). Tapi JANGAN PERNAH jangan sampai ada nilai yang longgar di sistem Anda yang berpotensi membawa kejutan.
Jika Null berada dalam domain nilai yang sesuai untuk model data Anda, tangani dengan tepat.
Ketika mengembalikan nilai, cobalah untuk tidak mengembalikan nol kapan pun memungkinkan. Selalu lebih suka daftar kosong, string kosong, pola objek kosong. Pertahankan nulls sebagai nilai yang dikembalikan saat ini adalah representasi data terbaik untuk kasus penggunaan tertentu.
Mungkin yang paling penting dari semuanya ... Tes, tes, dan tes lagi. Saat menguji kode Anda, jangan mengujinya sebagai pembuat kode, teskan itu sebagai dominatrix psikopat Nazi dan coba bayangkan segala macam cara untuk menyiksa kode itu.
Ini cenderung sedikit di sisi paranoid tentang nulls sering mengarah ke fasad dan proksi yang menghubungkan sistem ke dunia luar dan nilai-nilai yang dikontrol ketat di dalam dengan redundansi berlimpah. Dunia luar di sini berarti hampir semua yang saya sendiri tidak kode. Memang menanggung runtime biaya tetapi sejauh ini saya jarang harus mengoptimalkan ini dengan membuat "bagian aman nol" dari kode. Saya harus mengatakan bahwa saya kebanyakan membuat sistem berjalan lama untuk perawatan kesehatan dan hal terakhir yang saya inginkan adalah subsistem antarmuka yang membawa alergi yodium Anda ke pemindai CT macet karena null pointer yang tidak terduga karena orang lain dalam sistem lain tidak pernah menyadari bahwa nama dapat mengandung apostrof atau karakter seperti 但 耒耨。
lagian .... 2 sen saya
sumber
Saya akan mengusulkan menggunakan pola Option / Some / None dari bahasa fungsional. Saya bukan spesialis Java, tetapi saya secara intensif menggunakan implementasi saya sendiri dari pola ini dalam proyek C # saya, dan saya yakin itu bisa dikonversi ke dunia Java.
Gagasan di balik pola ini adalah: jika secara logis memiliki situasi ketika ada kemungkinan tidak adanya nilai (misalnya ketika mengambil kembali dari database dengan id) Anda memberikan objek dengan tipe Option [T], di mana T adalah nilai yang mungkin . I kasus tidak adanya objek nilai kelas Tidak ada [T] kembali, dalam kasus jika ada nilai - objek Beberapa [T] kembali, mengandung nilai.
Dalam hal ini, Anda harus menangani kemungkinan tidak adanya nilai, dan jika Anda melakukan peninjauan kode, Anda dapat dengan mudah menemukan placec penanganan yang salah. Untuk mendapatkan inspirasi dari implementasi bahasa C # lihat repositori bitbucket saya https://bitbucket.org/mikegirkin/optionsomenone
Jika Anda mengembalikan nilai nol, dan secara logis setara dengan kesalahan (misalnya tidak ada file, atau tidak dapat terhubung) Anda harus melempar pengecualian, atau menggunakan pola penanganan kesalahan lainnya. Gagasan di balik ini, sekali lagi, Anda berakhir dengan solusi, ketika Anda harus menangani situasi tidak adanya nilai, dan dapat dengan mudah menemukan tempat-tempat penanganan yang salah dalam kode.
sumber
Nah jika salah satu hasil yang mungkin dari metode Anda adalah nilai nol maka Anda harus kode defensif untuk itu, tetapi jika suatu metode seharusnya mengembalikan non-nol tetapi bukankah saya akan memperbaikinya pasti.
Seperti biasa itu tergantung pada kasusnya, seperti kebanyakan hal dalam hidup :)
sumber
Pustaka lang Apache Commons menyediakan cara untuk menangani nilai nol
metode defaultIfNull di kelas ObjectUtils memungkinkan Anda untuk mengembalikan nilai default jika objek yang dilewati adalah nol
sumber
Jangan menggunakan jenis Opsional, kecuali jika itu benar-benar opsional, sering kali jalan keluar lebih baik ditangani sebagai pengecualian, kecuali Anda benar-benar mengharapkan null sebagai opsi, dan bukan karena Anda secara teratur menulis kode kereta.
Masalahnya bukan nol sebagai jenis penggunaannya, seperti yang ditunjukkan artikel Google. Masalahnya adalah bahwa nulls harus diperiksa dan ditangani, seringkali mereka dapat keluar dengan anggun.
Ada sejumlah kasus nol yang mewakili kondisi tidak valid di area di luar operasi rutin program (input pengguna tidak valid, masalah database, kegagalan jaringan, file yang hilang, data korup), yang merupakan pengecualian untuk memeriksa, menangani mereka, bahkan jika itu hanya untuk login saja.
Penanganan pengecualian diizinkan berbagai prioritas dan hak istimewa operasional di JVM sebagai lawan dari jenis, seperti Opsional, yang masuk akal untuk sifat luar biasa dari kejadiannya, termasuk dukungan awal untuk pemuatan malas penangan pawang yang diprioritaskan ke dalam memori, karena Anda tidak membutuhkannya berkeliaran sepanjang waktu.
Anda tidak perlu menulis penangan nol di semua tempat, hanya di mana mereka mungkin terjadi, di mana pun Anda berpotensi mengakses layanan data yang tidak dapat diandalkan, dan karena sebagian besar ini jatuh ke dalam beberapa pola umum yang dapat dengan mudah diabstraksi, Anda hanya perlu panggilan pawang, kecuali dalam kasus yang jarang terjadi.
Jadi saya kira jawaban saya akan membungkusnya dalam pengecualian diperiksa dan menanganinya, atau memperbaiki kode tidak dapat diandalkan jika itu sesuai kemampuan Anda.
sumber