Saya menggunakan object != null
banyak hal untuk menghindari NullPointerException
.
Apakah ada alternatif yang baik untuk ini?
Misalnya saya sering menggunakan:
if (someobject != null) {
someobject.doCalc();
}
Ini pemeriksaan untuk NullPointerException
untuk someobject
objek dalam potongan di atas.
Perhatikan bahwa jawaban yang diterima mungkin kedaluwarsa, lihat https://stackoverflow.com/a/2386013/12943 untuk pendekatan yang lebih baru.
java
object
nullpointerexception
null
Goran Martinic
sumber
sumber
Option
tipe Scala yang luar biasa dirusak oleh keengganan bahasa untuk mengontrol atau melarangnull
. Saya menyebutkan ini di hackernews dan diturunkan dan mengatakan bahwa "toh tidak ada yang menggunakan null di Scala". Coba tebak, saya sudah menemukan nol di Scala yang ditulis rekan kerja. Ya, mereka "melakukan hal yang salah" dan harus dididik tentang hal itu, tetapi faktanya tetap sistem tipe bahasa harus melindungi saya dari ini dan itu tidak :(Jawaban:
Bagi saya ini terdengar seperti masalah umum yang cenderung dihadapi oleh pengembang menengah ke menengah: mereka tidak tahu atau tidak mempercayai kontrak yang mereka ikuti dan secara defensif memeriksa nol. Selain itu, ketika menulis kode mereka sendiri, mereka cenderung mengandalkan pengembalian nol untuk menunjukkan sesuatu sehingga membutuhkan pemanggil untuk memeriksa nol.
Dengan kata lain, ada dua contoh di mana pemeriksaan nol muncul:
Di mana null adalah respons yang valid dalam hal kontrak; dan
Di mana itu bukan respons yang valid.
(2) mudah. Baik menggunakan
assert
pernyataan (pernyataan) atau membiarkan kegagalan (misalnya, NullPointerException ). Pernyataan adalah fitur Java yang sangat kurang dimanfaatkan yang ditambahkan pada 1.4. Sintaksnya adalah:atau
di mana
<condition>
adalah ekspresi boolean dan<object>
merupakan objek yangtoString()
keluaran metodenya akan dimasukkan dalam kesalahan.Sebuah
assert
pernyataan melemparError
(AssertionError
) jika kondisi tidak benar. Secara default, Java mengabaikan pernyataan. Anda dapat mengaktifkan pernyataan dengan meneruskan opsi-ea
ke JVM. Anda dapat mengaktifkan dan menonaktifkan pernyataan untuk masing-masing kelas dan paket. Ini berarti bahwa Anda dapat memvalidasi kode dengan pernyataan sambil mengembangkan dan menguji, dan menonaktifkannya dalam lingkungan produksi, meskipun pengujian saya telah menunjukkan hampir tidak ada dampak kinerja dari pernyataan.Tidak menggunakan pernyataan dalam kasus ini OK karena kode hanya akan gagal, yang akan terjadi jika Anda menggunakan pernyataan. Satu-satunya perbedaan adalah bahwa dengan pernyataan itu mungkin terjadi lebih cepat, dengan cara yang lebih bermakna dan mungkin dengan informasi tambahan, yang dapat membantu Anda untuk mengetahui mengapa hal itu terjadi jika Anda tidak mengharapkannya.
(1) sedikit lebih sulit. Jika Anda tidak memiliki kendali atas kode yang Anda panggil maka Anda mandek. Jika null adalah respons yang valid, Anda harus memeriksanya.
Namun, jika itu kode yang Anda kontrol (dan ini sering terjadi), maka itu adalah cerita yang berbeda. Hindari menggunakan nulls sebagai respons. Dengan metode yang mengembalikan koleksi, mudah: kembalikan koleksi kosong (atau array) alih-alih nulls sepanjang waktu.
Dengan non-koleksi mungkin lebih sulit. Pertimbangkan ini sebagai contoh: jika Anda memiliki antarmuka ini:
di mana Parser mengambil input pengguna mentah dan menemukan sesuatu untuk dilakukan, mungkin jika Anda mengimplementasikan antarmuka baris perintah untuk sesuatu. Sekarang Anda dapat membuat kontrak yang mengembalikan nol jika tidak ada tindakan yang sesuai. Itu mengarah nol memeriksa Anda bicarakan.
Solusi alternatif adalah tidak pernah mengembalikan null dan sebaliknya menggunakan pola Objek Null :
Membandingkan:
untuk
yang merupakan desain yang jauh lebih baik karena mengarah ke kode yang lebih ringkas.
Yang mengatakan, mungkin itu sepenuhnya tepat untuk metode findAction () untuk membuang Pengecualian dengan pesan kesalahan yang bermakna - terutama dalam kasus ini di mana Anda mengandalkan input pengguna. Akan jauh lebih baik bagi metode findAction untuk melemparkan Exception daripada metode pemanggilan untuk meledakkan dengan NullPointerException sederhana tanpa penjelasan.
Atau jika Anda berpikir mekanisme coba / tangkap terlalu jelek, daripada Jangan Melakukan apa pun, tindakan default Anda harus memberikan umpan balik kepada pengguna.
sumber
Jika Anda menggunakan (atau berencana untuk menggunakan) IDE Java seperti JetBrains IntelliJ IDEA , Eclipse atau Netbeans atau alat seperti findbugs maka Anda dapat menggunakan anotasi untuk menyelesaikan masalah ini.
Pada dasarnya, Anda punya
@Nullable
dan@NotNull
.Anda dapat menggunakan metode dan parameter, seperti ini:
atau
Contoh kedua tidak akan dikompilasi (dalam IntelliJ IDEA).
Saat Anda menggunakan
helloWorld()
fungsi pertama di bagian kode yang lain:Sekarang kompiler IntelliJ IDEA akan memberi tahu Anda bahwa cek tidak berguna, karena
helloWorld()
fungsinya tidak akan kembalinull
, selamanya.Menggunakan parameter
jika Anda menulis sesuatu seperti:
Ini tidak akan dikompilasi.
Contoh terakhir menggunakan
@Nullable
Melakukan ini
Dan Anda dapat yakin bahwa ini tidak akan terjadi. :)
Ini adalah cara yang bagus untuk membiarkan kompiler memeriksa sesuatu lebih dari biasanya dan untuk menegakkan kontrak Anda menjadi lebih kuat. Sayangnya, itu tidak didukung oleh semua kompiler.
Dalam IntelliJ IDEA 10.5 dan seterusnya, mereka menambahkan dukungan untuk
@Nullable
@NotNull
implementasi lainnya .Lihat posting blog Lebih fleksibel dan dapat dikonfigurasi @ Nullable / @ NotNull annotations .
sumber
@NotNull
,@Nullable
dan anotasi nullness lainnya adalah bagian dari JSR 305 . Anda juga dapat menggunakannya untuk mendeteksi potensi masalah dengan alat-alat seperti FindBugs .@NotNull
&@Nullable
hidup dalam paketcom.sun.istack.internal
. (Saya kira saya mengaitkan com.sun dengan peringatan tentang menggunakan API berpemilik.)@NotNull
dan@Nullable
adalah bahwa mereka dengan baik menurun ketika kode sumber dibangun oleh sistem yang tidak memahaminya. Jadi, pada dasarnya, argumen bahwa kode ini tidak portabel mungkin tidak valid - jika Anda menggunakan sistem yang mendukung dan memahami anotasi ini, Anda mendapatkan manfaat tambahan dari pengecekan kesalahan yang lebih ketat, jika tidak Anda mendapatkan lebih sedikit tetapi kode Anda tetap harus build fine, dan kualitas program Anda yang berjalan SAMA, karena penjelasan ini tidak diberlakukan saat runtime. Selain itu, semua kompiler adalah custom ;-)Jika nilai nol tidak diizinkan
Jika metode Anda dipanggil secara eksternal, mulailah dengan sesuatu seperti ini:
Kemudian, di sisa metode itu, Anda akan tahu itu
object
bukan nol.Jika ini adalah metode internal (bukan bagian dari API), cukup dokumentasikan bahwa itu tidak boleh nol, dan hanya itu.
Contoh:
Namun, jika metode Anda hanya meneruskan nilainya, dan metode selanjutnya meneruskannya dll. Itu bisa bermasalah. Dalam hal ini Anda mungkin ingin memeriksa argumen seperti di atas.
Jika nol diizinkan
Ini sangat tergantung. Jika ternyata saya sering melakukan hal seperti ini:
Jadi saya bercabang, dan melakukan dua hal yang sangat berbeda. Tidak ada cuplikan kode yang jelek, karena saya benar-benar perlu melakukan dua hal berbeda tergantung pada datanya. Misalnya, apakah saya harus mengerjakan input, atau haruskah saya menghitung nilai default yang baik?
Sebenarnya jarang bagi saya untuk menggunakan idiom "
if (object != null && ...
".Mungkin lebih mudah untuk memberi Anda contoh, jika Anda menunjukkan contoh di mana Anda biasanya menggunakan idiom.
sumber
throw new IllegalArgumentException("object==null")
Wow, saya hampir benci menambahkan jawaban lain ketika kami memiliki 57 cara berbeda untuk merekomendasikannya
NullObject pattern
, tapi saya pikir beberapa orang yang tertarik dengan pertanyaan ini mungkin ingin tahu bahwa ada proposal di meja untuk Java 7 untuk menambahkan "null-safe handling " —sederhana sintaksis untuk logika if-not-equal-null.Contoh yang diberikan oleh Alex Miller terlihat seperti ini:
The
?.
berarti hanya de-referensi pengenal kiri jika tidak nol, jika tidak mengevaluasi sisa ekspresi sebagainull
. Beberapa orang, seperti anggota Jawa Posse, Dick Wall dan para pemilih di Devoxx sangat menyukai proposal ini, tetapi ada juga oposisi, dengan alasan bahwa hal itu akan mendorong lebih banyak penggunaannull
sebagai nilai sentinel.Update: Sebuah usulan resmi untuk operator null-aman di Jawa 7 telah diserahkan di bawah Proyek Coin. Sintaksnya sedikit berbeda dari contoh di atas, tetapi gagasannya sama.
Pembaruan: Proposal operator nol-aman tidak membuatnya menjadi Project Coin. Jadi, Anda tidak akan melihat sintaks ini di Java 7.
sumber
Jika nilai yang tidak ditentukan tidak diizinkan:
Anda dapat mengkonfigurasi IDE Anda untuk memperingatkan Anda tentang potensi nol dereferencing. Misalnya dalam Eclipse, lihat Preferensi> Java> Kompiler> Analisis Kesalahan / Peringatan / Null .
Jika nilai yang tidak ditentukan diizinkan:
Jika Anda ingin mendefinisikan API baru di mana nilai yang tidak terdefinisi masuk akal , gunakan Pola Opsi (mungkin terbiasa dengan bahasa fungsional). Ini memiliki keuntungan sebagai berikut:
Java 8 memiliki
Optional
kelas bawaan (disarankan); untuk versi sebelumnya, ada alternatif perpustakaan, misalnya Guava 'sOptional
atau FunctionalJava 'sOption
. Tetapi seperti banyak pola gaya fungsional, menggunakan Option di Java (bahkan 8) menghasilkan beberapa boilerplate, yang dapat Anda kurangi menggunakan bahasa JVM yang kurang verbose, misalnya Scala atau Xtend.Jika Anda harus berurusan dengan API yang mungkin mengembalikan nol , Anda tidak bisa berbuat banyak di Jawa. Xtend dan Groovy memiliki operator Elvis
?:
dan operator dereference null-safe?.
, tetapi perhatikan bahwa ini mengembalikan null jika ada referensi nol, jadi itu hanya "membela" penanganan null yang tepat.sumber
Hanya untuk situasi ini -
Tidak memeriksa apakah variabel nol sebelum memanggil metode sama dengan (contoh perbandingan string di bawah):
akan menghasilkan
NullPointerException
jikafoo
tidak ada.Anda dapat menghindarinya jika membandingkan
String
seperti ini:sumber
<object that you know that is not null>.equals(<object that might be null>);
. Ini berfungsi untuk metode lain selainequals
jika Anda mengetahui kontraknya dan metode tersebut dapat menanganinull
parameter.Dengan Java 8 hadir
java.util.Optional
kelas baru yang bisa dipecahkan beberapa masalah. Paling tidak orang dapat mengatakan bahwa itu meningkatkan keterbacaan kode, dan dalam kasus API publik membuat kontrak API lebih jelas kepada pengembang klien.Mereka bekerja seperti itu:
Objek opsional untuk tipe tertentu (
Fruit
) dibuat sebagai tipe pengembalian metode. Itu bisa kosong atau mengandungFruit
objek:Sekarang lihat kode ini di mana kita mencari daftar
Fruit
(fruits
) untuk contoh Buah yang diberikan:Anda dapat menggunakan
map()
operator untuk melakukan perhitungan pada - atau mengekstrak nilai dari - objek opsional.orElse()
memungkinkan Anda memberikan fallback untuk nilai yang hilang.Tentu saja, pemeriksaan untuk nilai nol / kosong masih diperlukan, tetapi setidaknya pengembang sadar bahwa nilai tersebut mungkin kosong dan risiko lupa untuk memeriksa terbatas.
Dalam API yang dibangun dari awal menggunakan
Optional
setiap kali nilai kembali mungkin kosong, dan mengembalikan objek polos hanya ketika itu tidak bisanull
(konvensi), kode klien mungkin mengabaikan cek nol pada nilai-nilai pengembalian objek sederhana ...Tentu saja
Optional
juga dapat digunakan sebagai argumen metode, mungkin cara yang lebih baik untuk menunjukkan argumen opsional dari 5 atau 10 metode kelebihan beban dalam beberapa kasus.Optional
menawarkan metode mudah lainnya, sepertiorElse
yang memungkinkan penggunaan nilai default, danifPresent
yang berfungsi dengan ekspresi lambda .Saya mengundang Anda untuk membaca artikel ini (sumber utama saya untuk menulis jawaban ini) di mana
NullPointerException
(dan secara umum null pointer) bermasalah serta solusi (parsial) yang dibawaOptional
dijelaskan dengan baik: Java Optional Objects .sumber
if(optional.isPresent()){ optional.get(); }
sebagai gantioptional.ifPresent(o -> { ...})
Bergantung pada objek apa yang Anda periksa, Anda mungkin dapat menggunakan beberapa kelas di apache commons seperti: apache commons lang dan koleksi apache commons
Contoh:
atau (tergantung pada apa yang perlu Anda periksa):
Kelas StringUtils hanya satu dari banyak; ada beberapa kelas bagus di commons yang melakukan manipulasi null aman.
Berikut ini contoh bagaimana Anda dapat menggunakan null vallidation di JAVA ketika Anda memasukkan pustaka apache (commons-lang-2.4.jar)
Dan jika Anda menggunakan Spring, Spring juga memiliki fungsi yang sama dalam paketnya, lihat pustaka (spring-2.4.6.jar)
Contoh tentang cara menggunakan classf statis ini dari musim semi (org.springframework.util.Assert)
sumber
Anda harus memeriksa objek! = Null hanya jika Anda ingin menangani case di mana objek tersebut mungkin nol ...
Ada proposal untuk menambahkan anotasi baru di Java7 untuk membantu dengan null / notnull params: http://tech.puredanger.com/java7/#jsr308
sumber
Saya penggemar kode "gagal cepat". Tanyakan pada diri sendiri - apakah Anda melakukan sesuatu yang bermanfaat dalam hal parameternya nol? Jika Anda tidak memiliki jawaban yang jelas untuk apa kode Anda harus dilakukan dalam kasus itu ... Ie itu tidak boleh nol di tempat pertama, maka abaikan saja dan biarkan NullPointerException dilempar. Kode panggilan akan masuk akal seperti NPE seperti halnya IllegalArgumentException, tetapi akan lebih mudah bagi pengembang untuk men-debug dan memahami apa yang salah jika NPE dilempar daripada kode Anda yang berusaha mengeksekusi kemungkinan tak terduga lainnya logika - yang pada akhirnya menyebabkan aplikasi gagal.
sumber
Kerangka kerja koleksi Google menawarkan cara yang baik dan elegan untuk mencapai pemeriksaan nol.
Ada metode di kelas perpustakaan seperti ini:
Dan penggunaannya adalah
import static
:Atau dalam contoh Anda:
sumber
getThing().getItsThing().getOtherThing().wowEncapsulationIsBroken().setLol("hi");
Terkadang, Anda memiliki metode yang beroperasi pada parameternya yang menentukan operasi simetris:
Jika Anda tahu b tidak pernah bisa menjadi nol, Anda bisa menukarnya. Ini paling berguna untuk yang sederajat: Alih-alih
foo.equals("bar");
melakukannya dengan lebih baik"bar".equals(foo);
.sumber
equals
(bisa berupa metode apa saja) akan menangani null dengan benar. Sebenarnya yang dilakukan adalah menyerahkan tanggung jawab kepada orang lain (atau metode lain).equals
(atau metode apa pun) harus memeriksanull
. Atau nyatakan secara eksplisit bahwa tidak.Daripada Null Object Pattern - yang memiliki kegunaannya - Anda dapat mempertimbangkan situasi di mana objek nol adalah bug.
Ketika pengecualian dilemparkan, periksa jejak tumpukan dan bekerja melalui bug.
sumber
Null bukan 'masalah'. Ini adalah bagian integral dari set alat pemodelan lengkap . Perangkat lunak bertujuan untuk memodelkan kompleksitas dunia dan null menanggung bebannya. Null menunjukkan 'Tidak ada data' atau 'Tidak dikenal' di Jawa dan sejenisnya. Jadi pantas menggunakan nulls untuk tujuan ini. Saya tidak suka pola 'objek kosong'; Saya pikir itu muncul masalah ' siapa yang akan menjaga wali '.
Jika Anda bertanya kepada saya apa nama pacar saya, saya akan memberi tahu Anda bahwa saya tidak punya pacar. Dalam bahasa Java saya akan mengembalikan null. Alternatifnya adalah dengan melemparkan pengecualian yang berarti untuk menunjukkan beberapa masalah yang tidak dapat (atau tidak
Untuk 'pertanyaan tidak dikenal', berikan 'jawaban tidak dikenal'. (Jadilah null-safe di mana ini benar dari sudut pandang bisnis) Memeriksa argumen untuk nol sekali di dalam suatu metode sebelum penggunaan membebaskan beberapa penelepon dari memeriksa mereka sebelum panggilan.
Sebelumnya mengarah ke aliran logika normal untuk tidak mendapatkan foto pacar yang tidak ada dari perpustakaan foto saya.
Dan itu cocok dengan Java API baru yang akan datang (menantikan)
Walaupun agak 'aliran bisnis normal' untuk tidak menemukan foto yang disimpan dalam DB untuk beberapa orang, saya biasa menggunakan pasangan seperti di bawah ini untuk beberapa kasus lain
Dan jangan benci mengetik
<alt> + <shift> + <j>
(menghasilkan javadoc di Eclipse) dan menulis tiga kata tambahan untuk Anda API publik. Ini akan lebih dari cukup untuk semua kecuali mereka yang tidak membaca dokumentasi.atau
Ini adalah kasus yang agak teoretis dan dalam kebanyakan kasus Anda lebih suka java null safe API (dalam kasus ini akan dirilis dalam 10 tahun lagi), tetapi
NullPointerException
merupakan subkelas dariException
. Jadi itu adalah bentukThrowable
yang menunjukkan kondisi yang mungkin ingin ditangkap oleh aplikasi yang masuk akal ( javadoc )! Untuk menggunakan sebagian besar keuntungan pertama dari pengecualian dan memisahkan kode penanganan kesalahan dari kode 'biasa' ( menurut pencipta Jawa ) adalah tepat, bagi saya, untuk menangkapNullPointerException
.Pertanyaan dapat muncul:
Q. Bagaimana jika
getPhotoDataSource()
pengembalian nol?A. Terserah logika bisnis. Jika saya gagal menemukan album foto saya tidak akan menunjukkan foto. Bagaimana jika appContext tidak diinisialisasi? Logika bisnis metode ini cocok dengan ini. Jika logika yang sama harus lebih ketat maka melemparkan pengecualian itu adalah bagian dari logika bisnis dan pemeriksaan eksplisit untuk null harus digunakan (kasus 3). The cocok Java Null-aman API baru yang lebih baik di sini untuk menentukan selektif apa yang menyiratkan dan apa tidak berarti harus diinisialisasi menjadi gagal-cepat jika terjadi kesalahan programmer.
P. Kode redundan dapat dieksekusi dan sumber daya yang tidak perlu bisa diambil.
A. Itu bisa terjadi jika
getPhotoByName()
akan mencoba untuk membuka koneksi database, membuatPreparedStatement
dan menggunakan nama orang sebagai parameter SQL pada akhirnya. Pendekatan untuk pertanyaan yang tidak diketahui memberikan jawaban yang tidak diketahui (kasus 1) bekerja di sini. Sebelum mengambil sumber daya, metode ini harus memeriksa parameter dan mengembalikan hasil 'tidak dikenal' jika diperlukan.Q. Pendekatan ini memiliki penalti kinerja karena pembukaan penutupan percobaan.
A. Perangkat lunak harus mudah dipahami dan dimodifikasi terlebih dahulu. Hanya setelah ini, orang dapat berpikir tentang kinerja, dan hanya jika diperlukan! dan di mana dibutuhkan! ( sumber ), dan banyak lainnya).
PS. Pendekatan ini akan masuk akal untuk digunakan karena kode penanganan kesalahan yang terpisah dari prinsip kode "biasa" masuk akal untuk digunakan di beberapa tempat. Perhatikan contoh berikut:
PPS. Bagi mereka yang cepat downvote (dan tidak terlalu cepat membaca dokumentasi) saya ingin mengatakan bahwa saya tidak pernah menangkap pengecualian null-pointer (NPE) dalam hidup saya. Tetapi kemungkinan ini sengaja dirancang oleh pencipta Jawa karena NPE adalah subkelas dari
Exception
. Kami memiliki preseden dalam sejarah Jawa saatThreadDeath
adalahError
tidak karena sebenarnya kesalahan aplikasi, tetapi semata-mata karena itu tidak dimaksudkan untuk ditangkap! Berapa banyak NPE yang cocok menjadiError
daripadaThreadDeath
! Tapi ternyata tidak.Periksa 'Tidak ada data' hanya jika logika bisnis menyiratkannya.
dan
Jika appContext atau dataSource tidak diinisialisasi runtime yang tidak ditangani, NullPointerException akan mematikan utas saat ini dan akan diproses oleh Thread.defaultUncaughtExceptionHandler (untuk Anda menentukan dan menggunakan logger favorit Anda atau mekanisme pemberitahuan lainnya). Jika tidak disetel, ThreadGroup # uncaughtException akan mencetak stacktrace ke kesalahan sistem. Seseorang harus memonitor log kesalahan aplikasi dan membuka masalah Jira untuk setiap pengecualian yang tidak tertangani yang sebenarnya adalah kesalahan aplikasi. Programmer harus memperbaiki bug di suatu tempat dalam hal inisialisasi.
sumber
NullPointerException
dan kembalinull
mengerikan untuk debug. Lagi pula, Anda berakhir dengan NPE, dan sangat sulit untuk mengetahui apa yang semula nol.if (maybeNull.hasValue()) {...}
apa bedanyaif (maybeNull != null)) {...}
?Maybe<T>
atauOptional<T>
tidak dalam kasus di mana AndaT
mungkin nol, tetapi dalam kasus di mana seharusnya tidak boleh nol. Jika Anda memiliki jenis yang secara eksplisit berarti "nilai ini mungkin nol - gunakan dengan hati-hati", dan Anda menggunakan dan mengembalikan jenis seperti itu secara konsisten, maka setiap kali Anda melihat polos lamaT
dalam kode Anda, Anda dapat menganggap itu tidak pernah nol. (Tentu saja, ini akan jauh lebih berguna jika diberlakukan oleh kompiler.)Java 7 memiliki
java.util.Objects
kelas utilitas baru di mana adarequireNonNull()
metode. Yang dilakukan adalah membuangNullPointerException
argumennya jika null, tetapi sedikit membersihkan kode. Contoh:Metode ini paling berguna untuk memeriksa sesaat sebelum penugasan dalam konstruktor, di mana setiap penggunaannya dapat menyimpan tiga baris kode:
menjadi
sumber
doCalc(someObject)
.doCalc()
, dan itu tidak langsung melempar NPE ketika diberi nol, Anda harus memeriksa nol dan melemparkan NPE sendiri. Itu untuk apaObjects.requireNonNull()
.Pada akhirnya, satu-satunya cara untuk menyelesaikan masalah ini adalah dengan menggunakan bahasa pemrograman yang berbeda:
nil
, dan sama sekali tidak akan terjadi apa-apa. Ini membuat sebagian besar pemeriksaan nol tidak perlu, tetapi dapat membuat kesalahan lebih sulit untuk didiagnosis.sumber
"Masalah" yang biasa terjadi di Jawa.
Pertama, pikiran saya tentang ini:
Saya menganggap itu buruk untuk "makan" sesuatu ketika NULL disahkan di mana NULL bukan nilai yang valid. Jika Anda tidak keluar dari metode dengan semacam kesalahan maka itu berarti tidak ada yang salah dalam metode Anda yang tidak benar. Maka Anda mungkin mengembalikan nol dalam kasus ini, dan dalam metode penerimaan Anda kembali memeriksa nol, dan itu tidak pernah berakhir, dan Anda berakhir dengan "jika! = Null", dll.
Jadi, IMHO, null harus merupakan kesalahan kritis yang mencegah eksekusi lebih lanjut (yaitu, di mana null bukan nilai yang valid).
Cara saya mengatasi masalah ini adalah ini:
Pertama, saya mengikuti konvensi ini:
Dan akhirnya, dalam kode, baris pertama dari metode publik berbunyi seperti ini:
Perhatikan bahwa addParam () mengembalikan diri, sehingga Anda dapat menambahkan lebih banyak parameter untuk memeriksa.
Metode
validate()
akan membuang diperiksaValidationException
jika salah satu parameter adalah nol (dicentang atau tidak dicentang lebih merupakan masalah desain / rasa, tapi sayaValidationException
diperiksa).Pesan akan berisi teks berikut jika, misalnya, "paket" adalah nol:
" Nilai argumen ilegal null ditemukan untuk parameter [paket] "
Seperti yang Anda lihat, nilai kedua dalam metode addParam () (string) diperlukan untuk pesan pengguna, karena Anda tidak dapat dengan mudah mendeteksi nama variabel yang diteruskan, bahkan dengan refleksi (toh bukan subjek dari posting ini ...).
Dan ya, kita tahu bahwa di luar garis ini kita tidak akan lagi menemukan nilai nol sehingga kita hanya dengan aman memanggil metode pada objek tersebut.
Dengan cara ini, kodenya bersih, mudah dirawat dan dapat dibaca.
sumber
Mengajukan pertanyaan itu menunjukkan bahwa Anda mungkin tertarik dengan strategi penanganan kesalahan. Arsitek tim Anda harus memutuskan cara mengatasi kesalahan. Ada beberapa cara untuk melakukan ini:
memungkinkan Pengecualian untuk beriak - tangkap di 'loop utama' atau dalam beberapa rutinitas pengelolaan lainnya.
Tentu saja lihat Pemrograman Berorientasi Aspek, juga - mereka memiliki cara rapi untuk memasukkan
if( o == null ) handleNull()
ke dalam bytecode Anda.sumber
Selain menggunakan
assert
Anda dapat menggunakan yang berikut:Ini sedikit lebih baik daripada:
sumber
if (!something) { x(); } else { y(); }
saya akan cenderung untuk refactor sebagaiif (something) { y(); } else { x(); }
(meskipun orang dapat berpendapat bahwa itu!= null
adalah pilihan yang lebih positif ...) Tetapi yang lebih penting, bagian penting dari kode tidak dibungkus di dalam{}
dan Anda memiliki satu lekukan tingkat kurang untuk sebagian besar metode. Saya tidak tahu apakah itu alasan fastcodejava tapi itu akan menjadi milik saya.Hanya saja jangan pernah menggunakan null. Jangan izinkan.
Di kelas saya, sebagian besar bidang dan variabel lokal memiliki nilai default non-nol, dan saya menambahkan pernyataan kontrak (selalu-on menegaskan) di mana pun dalam kode untuk memastikan ini ditegakkan (karena lebih ringkas, dan lebih ekspresif daripada membiarkannya muncul sebagai NPE dan kemudian harus menyelesaikan nomor baris, dll.).
Begitu saya mengadopsi praktik ini, saya perhatikan bahwa masalah-masalah itu sepertinya memperbaiki diri. Anda akan menangkap banyak hal lebih awal dalam proses pengembangan hanya secara tidak sengaja dan menyadari bahwa Anda memiliki titik lemah .. dan yang lebih penting .. ini membantu merangkum keprihatinan modul yang berbeda, modul yang berbeda dapat saling 'percaya', dan tidak lagi membuang sampah sembarangan kode dengan
if = null else
konstruk!Ini adalah pemrograman defensif dan menghasilkan kode yang lebih bersih dalam jangka panjang. Selalu bersihkan data, misalnya di sini dengan menegakkan standar yang kaku, dan masalahnya hilang.
Kontrak seperti tes unit mini yang selalu berjalan, bahkan dalam produksi, dan ketika semuanya gagal, Anda tahu mengapa, daripada NPE acak Anda harus entah bagaimana mencari tahu.
sumber
Guava, pustaka inti yang sangat berguna oleh Google, memiliki API yang bagus dan berguna untuk menghindari nulls. Saya menemukan UsingAndAvoidingNullExplained sangat membantu.
Seperti yang dijelaskan di wiki:
Pemakaian:
sumber
Ini adalah masalah yang sangat umum untuk setiap pengembang Java. Jadi ada dukungan resmi di Java 8 untuk mengatasi masalah ini tanpa kode yang berantakan.
Java 8 telah diperkenalkan
java.util.Optional<T>
. Ini adalah wadah yang mungkin atau mungkin tidak memiliki nilai bukan nol. Java 8 telah memberikan cara yang lebih aman untuk menangani objek yang nilainya mungkin nol dalam beberapa kasus. Ini terinspirasi dari ide-ide Haskell dan Scala .Singkatnya, kelas opsional mencakup metode untuk secara eksplisit menangani kasus-kasus di mana nilai hadir atau tidak ada. Namun, keuntungan dibandingkan dengan referensi nol adalah bahwa kelas <T> opsional memaksa Anda untuk memikirkan kasus ketika nilainya tidak ada. Sebagai konsekuensinya, Anda dapat mencegah pengecualian null pointer yang tidak diinginkan.
Dalam contoh di atas kami memiliki pabrik layanan rumah yang mengembalikan pegangan ke beberapa peralatan yang tersedia di rumah. Tetapi layanan ini mungkin atau mungkin tidak tersedia / fungsional; itu berarti dapat menghasilkan NullPointerException. Alih-alih menambahkan
if
kondisi nol sebelum menggunakan layanan apa pun, mari membungkusnya dengan Opsional <Layanan>.Bungkus DENGAN OPSI <T>
Mari pertimbangkan metode untuk mendapatkan referensi layanan dari pabrik. Alih-alih mengembalikan referensi layanan, bungkus dengan Opsional. Ini memberi tahu pengguna API bahwa layanan yang dikembalikan mungkin atau mungkin tidak tersedia / berfungsi, gunakan secara defensif
Seperti yang Anda lihat
Optional.ofNullable()
memberikan cara mudah untuk mendapatkan referensi dibungkus. Ada cara lain untuk mendapatkan referensi Opsional, baikOptional.empty()
&Optional.of()
. Satu untuk mengembalikan objek kosong alih-alih mengembalikan nol dan yang lainnya untuk membungkus objek yang tidak dapat dibatalkan, masing-masing.BEGITU BAGAIMANA ITU MEMBANTU UNTUK MENGHINDARI NULL CHECK?
Setelah Anda membungkus objek referensi, Opsional menyediakan banyak metode yang berguna untuk memanggil metode pada referensi yang dibungkus tanpa NPE.
Optional.ifPresent memanggil Konsumen yang diberikan dengan referensi jika itu adalah nilai non-nol. Kalau tidak, ia tidak melakukan apa-apa.
Merupakan operasi yang menerima argumen input tunggal dan tidak mengembalikan hasil. Tidak seperti kebanyakan antarmuka fungsional lainnya, Konsumen diharapkan beroperasi melalui efek samping. Sangat bersih dan mudah dimengerti. Dalam contoh kode di atas,
HomeService.switchOn(Service)
dipanggil jika referensi penahanan opsional adalah bukan nol.Kami sangat sering menggunakan operator ternary untuk memeriksa kondisi nol dan mengembalikan nilai alternatif atau nilai default. Opsional menyediakan cara lain untuk menangani kondisi yang sama tanpa memeriksa nol. Optional.orElse (defaultObj) mengembalikan defaultObj jika Opsional memiliki nilai nol. Mari kita gunakan ini dalam kode sampel kami:
Sekarang HomeServices.get () melakukan hal yang sama, tetapi dengan cara yang lebih baik. Ia memeriksa apakah layanan sudah diinisialisasi belum. Jika kemudian mengembalikan yang sama atau membuat layanan baru. Opsional <T> .orElse (T) membantu mengembalikan nilai default.
Akhirnya, inilah NPE kami dan juga kode bebas-cek nol:
Posting lengkapnya adalah NPE dan juga kode bebas-cek Null… Benarkah? .
sumber
if(homeServices != null) {
yang dapat diubah menjadihomeServices.ifPresent(h -> //action)
;Saya suka artikel dari Nat Pryce. Inilah tautannya:
Dalam artikel tersebut ada juga tautan ke repositori Git untuk Java Maybe Type yang menurut saya menarik, tetapi saya tidak berpikir itu sendiri dapat mengurangi mengasapi kode pemeriksaan. Setelah melakukan riset di Internet, saya pikir ! = Kode nol mengasapi dapat dikurangi terutama dengan desain yang cermat.
sumber
Saya sudah mencoba
NullObjectPattern
tetapi bagi saya tidak selalu cara terbaik untuk pergi. Terkadang ada "tidak ada tindakan" yang tidak sesuai.NullPointerException
adalah pengecualian Runtime yang berarti kesalahan pengembang dan dengan pengalaman yang cukup itu memberi tahu Anda persis di mana kesalahannya.Sekarang untuk jawabannya:
Cobalah untuk membuat semua atribut Anda dan aksesornya se-privat mungkin atau hindari untuk mengungkapkannya kepada klien sama sekali. Anda dapat memiliki nilai argumen di konstruktor tentu saja, tetapi dengan mengurangi ruang lingkup Anda tidak membiarkan kelas klien melewati nilai yang tidak valid. Jika Anda perlu mengubah nilai, Anda selalu dapat membuat yang baru
object
. Anda memeriksa nilai-nilai di konstruktor hanya sekali dan di seluruh metode Anda dapat hampir yakin bahwa nilai-nilai tidak nol.Tentu saja, pengalaman adalah cara yang lebih baik untuk memahami dan menerapkan saran ini.
Byte!
sumber
Mungkin alternatif terbaik untuk Java 8 atau yang lebih baru adalah menggunakan
Optional
kelas.Ini sangat berguna untuk rantai panjang nilai null yang mungkin. Contoh:
Contoh tentang cara melempar pengecualian pada null:
Java 7 memperkenalkan
Objects.requireNonNull
metode yang bisa berguna ketika sesuatu harus diperiksa untuk tidak null. Contoh:sumber
Bolehkah saya menjawabnya secara lebih umum!
Kami biasanya menghadapi masalah ini ketika metode mendapatkan parameter dengan cara yang tidak kami harapkan (panggilan metode buruk adalah kesalahan programmer). Misalnya: Anda berharap mendapatkan objek, sebaliknya Anda mendapatkan nol. Anda berharap mendapatkan string dengan setidaknya satu karakter, alih-alih Anda mendapatkan String kosong ...
Jadi tidak ada perbedaan antara:
}
atau
Mereka berdua ingin memastikan bahwa kami menerima parameter yang valid, sebelum kami melakukan fungsi lain.
Seperti disebutkan dalam beberapa jawaban lain, untuk menghindari masalah di atas Anda dapat mengikuti Desain dengan pola kontrak . Silakan lihat http://en.wikipedia.org/wiki/Design_by_contract .
Untuk menerapkan pola ini di java, Anda dapat menggunakan penjelasan inti java seperti javax.annotation.NotNull atau menggunakan perpustakaan yang lebih canggih seperti Hibernate Validator .
Hanya sampel:
Sekarang Anda dapat dengan aman mengembangkan fungsi inti dari metode Anda tanpa perlu memeriksa parameter input, mereka menjaga metode Anda dari parameter yang tidak terduga.
Anda dapat melangkah lebih jauh dan memastikan bahwa hanya pojo yang valid yang dapat dibuat di aplikasi Anda. (contoh dari situs validator hibernasi)
sumber
javax
menurut definisi, bukan "Java inti".Saya sangat mengabaikan jawaban yang menyarankan menggunakan objek nol dalam setiap situasi. Pola ini dapat memutus kontrak dan mengubur masalah lebih dalam dan lebih dalam daripada menyelesaikannya, tidak menyebutkan bahwa penggunaan yang tidak tepat akan membuat tumpukan kode boilerplate lain yang akan membutuhkan pemeliharaan di masa depan.
Pada kenyataannya jika sesuatu yang dikembalikan dari suatu metode bisa menjadi nol dan kode panggilan harus membuat keputusan tentang itu, harus ada panggilan sebelumnya yang memastikan keadaan.
Juga perlu diingat, bahwa pola objek nol akan menjadi haus memori jika digunakan tanpa perawatan. Untuk ini - instance dari NullObject harus dibagikan di antara pemilik, dan tidak menjadi instance unigue untuk masing-masing.
Juga saya tidak akan merekomendasikan menggunakan pola ini di mana tipe dimaksudkan untuk representasi tipe primitif - seperti entitas matematika, yang tidak skalar: vektor, matriks, bilangan kompleks, dan objek POD (Data Lama Biasa), yang dimaksudkan untuk menahan keadaan dalam bentuk tipe bawaan Java. Dalam kasus terakhir Anda akan memanggil metode pengambil dengan hasil yang sewenang-wenang. Misalnya apa yang harus dikembalikan oleh metode NullPerson.getName ()?
Ada baiknya mempertimbangkan kasus-kasus seperti itu untuk menghindari hasil yang absurd.
sumber
Melakukan ini dalam kode Anda sendiri dan Anda dapat menghindari! = Cek kosong.
Sebagian besar waktu, cek nol tampaknya menjaga loop atas koleksi atau array, jadi inisialisasi saja kosong, Anda tidak akan memerlukan pemeriksaan nol.
Ada overhead kecil dalam hal ini, tetapi itu layak untuk kode yang lebih bersih dan lebih sedikit NullPointerExceptions.
sumber
Ini adalah kesalahan paling umum terjadi untuk sebagian besar pengembang.
Kami memiliki sejumlah cara untuk menangani ini.
Pendekatan 1:
notNull (Objek objek, pesan String)
Pendekatan 2:
Pendekatan 3:
Pendekatan 4:
sumber
sumber
ObjectUtils.defaultIfNull()
. Ada satu yang lebih umumObjectUtils.firstNonNull()
firstNonNull(bestChoice, secondBest, thirdBest, fallBack);