it-swarm-id.com

Cara terbaik untuk menangani null di Jawa?

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 membela 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?

21
Shaun F

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 adalah tidak input yang masuk akal.

45
user281377

Jangan gunakan null, gunakan Opsional

Seperti yang telah Anda tunjukkan, salah satu masalah terbesar dengan null di Java adalah dapat digunakan di mana-mana, atau setidaknya untuk semua jenis referensi.

Tidak mungkin mengatakan bahwa itu bisa null dan apa yang tidak bisa.

Java 8 memperkenalkan pola yang jauh lebih baik: Optional.

Dan contoh dari Oracle:

String version = "UNKNOWN";
if(computer != null) {
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null) {
    USB usb = soundcard.getUSB();
    if(usb != null) {
      version = usb.getVersion();
    }
  }
}

Jika masing-masing dari ini dapat atau tidak dapat mengembalikan nilai yang berhasil, Anda dapat mengubah API menjadi Optionals:

String name = computer.flatMap(Computer::getSoundcard)
    .flatMap(Soundcard::getUSB)
    .map(USB::getVersion)
    .orElse("UNKNOWN");

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 melihat 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 menjadi nol, dengan contoh-contoh dari beberapa bahasa: https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/


@ Nonnull, @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 yang memeriksa nol, terutama jika tidak ada yang masuk akal yang dapat dilakukan oleh kode Anda dengan nilai null.

Di sisi lain, jika null dapat digunakan dan memiliki arti, pastikan untuk menggunakannya.


Pada akhirnya, Anda jelas tidak dapat menghapus null dari Java. Saya sangat menyarankan untuk mengganti abstraksi Optional kapan pun memungkinkan, dan memeriksa null saat-saat lain Anda dapat melakukan sesuatu yang masuk akal.

21
Paul Draper

Ada beberapa cara untuk menangani hal ini, menambahkan kode Anda dengan if (obj != null) {} tidak ideal, berantakan, menambah derau saat membaca kode nanti selama siklus pemeliharaan dan rentan kesalahan, karena mudah dilupakan untuk melakukan pembungkus piring boiler ini.

Itu tergantung pada apakah Anda ingin kode untuk terus mengeksekusi diam-diam atau gagal. Apakah null 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. a null String tidak sama dengan kosong String, null int tidak sama dengan NOL, dalam teori. Dalam prakteknya "itu tergantung". Kosong String dapat membuat implementasi Null Object Yang bagus untuk kelas String, untuk Integer itu tergantung pada logika bisnis.

Alternatifnya adalah:

  1. Pola Null Object . Buat instance objek Anda yang mewakili keadaan null, dan inisialisasi semua referensi ke tipe itu dengan referensi ke implementasi Null. Ini berguna untuk objek tipe nilai sederhana yang tidak memiliki banyak referensi ke objek lain yang juga bisa null dan diharapkan menjadi null sebagai status yang valid.

  2. Gunakan alat Berorientasi Aspek untuk menenun metode dengan aspek Null Checker Yang mencegah parameter menjadi nol. Ini untuk kasus di mana null adalah kesalahan.

  3. Gunakan assert() tidak jauh lebih baik dari if (obj != null){} tetapi lebih sedikit noise.

  4. Gunakan alat Penegakan Kontrak seperti Kontrak Untuk Java . 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 dikenal sebagai 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 adalah generator Exception alternatif yang nyaman untuk menggantikan NullPointerException dengan sesuatu yang lebih informatif, yang selalu dan perbaikan.

Pada Akhirnya

null dalam Java hampir dalam semua kasus merupakan kesalahan logika. Anda harus selalu berusaha menghilangkan akar penyebab dari NullPointerExceptions. Anda harus berusaha keras untuk tidak menggunakan null mengkondisikan sebagai logika bisnis. if (x == null) { i = someDefault; } hanya membuat asistensi awal untuk instance objek default tersebut.

8
user7519

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

class House(Door door){

    .. null check here and throw exception if Door is NULL
    this.door = door
}

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, ruang tes Anda harus cukup kuat untuk menguji Pintu, Rumah, Atap atau apa pun tanpa harus paranoid tentang hal itu. 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

8
Constantin

tl; dr - BAIK untuk memeriksa nulls yang tak terduga tetapi BURUK untuk aplikasi agar membuatnya bagus.

Detail

Jelas, ada situasi di mana null adalah input atau output yang valid untuk suatu metode, dan lain-lain yang tidak.

Aturan # 1:

Javadoc untuk metode yang memungkinkan parameter null atau mengembalikan nilai null harus mendokumentasikan ini dengan jelas, dan menjelaskan apa arti null.

Aturan # 2:

Metode API tidak boleh ditentukan sebagai menerima atau mengembalikan null kecuali ada alasan yang baik untuk melakukannya.

Dengan spesifikasi yang jelas dari "kontrak" metode vis-a-vis nulls, ini merupakan kesalahan pemrograman untuk meneruskan atau mengembalikan null di mana Anda seharusnya tidak.

Aturan # 3:

Aplikasi seharusnya tidak berusaha untuk "membuat kesalahan pemrograman".

Jika suatu metode mendeteksi null yang seharusnya tidak ada di sana, metode itu seharusnya tidak berusaha memperbaiki masalah dengan mengubahnya menjadi sesuatu yang lain. Itu hanya menyembunyikan masalah dari programmer. Sebaliknya, itu 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 memungkinkan, tulis kode Anda untuk mendeteksi kesalahan pemrograman lebih awal.

Jika Anda memiliki bug dalam kode Anda yang menghasilkan banyak NPE, hal yang paling sulit adalah mencari tahu dari mana nilai-nilai null berasal. Salah satu cara untuk membuat diagnosis lebih mudah adalah dengan menulis kode Anda sehingga null terdeteksi sesegera mungkin. Seringkali Anda dapat melakukan ini bersamaan dengan cek lainnya; misalnya.

public setName(String name) {
    // This also detects `null` as an (intended) side-effect
    if (name.length() == 0) {
        throw new IllegalArgumentException("empty name");
    }
}

(Jelas ada kasus di mana aturan 3 dan 4 harus diimbangi dengan kenyataan. Misalnya (aturan 3), beberapa jenis aplikasi harus mencoba untuk melanjutkan setelah mendeteksi kemungkinan kesalahan pemrograman. Dan (aturan 4) terlalu banyak memeriksa parameter yang buruk dapat berdampak kinerja.)

4
Stephen C

Saya akan merekomendasikan memperbaiki metode menjadi defensif. Contohnya:

String go(String s){  
    return s.toString();  
}

Harus lebih seperti ini:

String go(String s){  
    if(s == null){  
       return "";  
    }     
    return s.toString();  
}

Saya menyadari ini benar-benar sepele, tetapi jika penyerang mengharapkan suatu objek memberi mereka objek default yang tidak akan menyebabkan nol untuk diteruskan.

3
Woot4Moo

Aturan umum berikut tentang null telah banyak membantu saya sejauh ini:

  1. 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 tersebut 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.

  2. Jika Null berada dalam domain nilai yang sesuai untuk model data Anda, tangani dengan tepat.

  3. 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.

  4. Mungkin yang paling penting dari semuanya ... Tes, tes, dan tes lagi. Saat menguji kode Anda, jangan mengujinya sebagai pembuat kode, mengujinya sebagai dominatrix psikopat Nazi dan mencoba membayangkan 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 yang berlimpah. Dunia luar di sini berarti hampir semua yang tidak saya kode sendiri. 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

2
Newtopian

Saya akan mengusulkan menggunakan opsi/Some/None pola dari bahasa fungsional. Saya bukan Java spesialis, tapi saya secara intensif menggunakan implementasi saya sendiri dari pola ini dalam proyek C # saya, dan saya yakin itu bisa dikonversi menjadi Java dunia.

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 tipe ketik [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, berisi nilai.

Dalam hal ini, Anda harus menangani kemungkinan tidak adanya nilai, dan jika Anda melakukan review 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 logika setara dengan kesalahan (misalnya tidak ada file, atau tidak dapat terhubung) Anda harus melempar pengecualian, atau menggunakan pola penanganan kesalahan lain. Gagasan di balik ini, sekali lagi, Anda berakhir dengan solusi, ketika Anda harus menangani situasi tidak adanya nilai, dan dapat dengan mudah menemukan tempat penanganan yang salah dalam kode.

1
Hedin
  1. 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.

  2. 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.

  3. Ada sejumlah kasus nol yang mewakili kondisi tidak valid di area di luar operasi rutin program (input pengguna yang tidak valid, masalah database, kegagalan jaringan, file yang hilang, data korup), yang merupakan pengecualian untuk memeriksa, menangani mereka, bahkan jika hanya untuk login saja.

  4. Penanganan pengecualian diizinkan berbagai prioritas operasional dan hak istimewa dalam 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.

  5. 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.

0
J-Boss

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 :)

0
jonezy

Apache Commons ' lang perpustakaan menyediakan cara untuk menangani nilai null

metode defaultIfNull di kelas ObjectUtils memungkinkan Anda untuk mengembalikan nilai default jika objek yang dikirimkan adalah nol

0
Mahmoud Hossam