Saya mencari rekomendasi di sini. Saya berjuang dengan apakah lebih baik mengembalikan NULL atau nilai kosong dari suatu metode ketika nilai kembali tidak ada atau tidak dapat ditentukan.
Ambil dua metode berikut sebagai contoh:
string ReverseString(string stringToReverse) // takes a string and reverses it.
Person FindPerson(int personID) // finds a Person with a matching personID.
Dalam ReverseString()
, saya akan mengatakan mengembalikan string kosong karena tipe kembali adalah string, jadi pemanggil mengharapkan itu. Selain itu, dengan cara ini, penelepon tidak perlu memeriksa untuk melihat apakah NULL dikembalikan.
Dalam FindPerson()
, mengembalikan NULL sepertinya lebih cocok. Terlepas dari apakah NULL atau Objek Orang kosong ( new Person()
) dikembalikan, pemanggil harus memeriksa untuk melihat apakah Objek Orang NULL atau kosong sebelum melakukan sesuatu untuk itu (seperti menelepon UpdateName()
). Jadi mengapa tidak mengembalikan NULL di sini dan kemudian penelepon hanya perlu memeriksa NULL.
Apakah ada orang lain yang berjuang dengan ini? Bantuan atau wawasan apa pun dihargai.
Jawaban:
StackOverflow memiliki diskusi yang baik tentang topik yang tepat ini di T&J ini . Dalam pertanyaan berperingkat teratas, Krono mencatat:
Secara pribadi, saya suka mengembalikan string kosong untuk fungsi yang mengembalikan string untuk meminimalkan jumlah penanganan kesalahan yang perlu dilakukan. Namun, Anda harus memastikan bahwa grup yang bekerja dengan Anda akan mengikuti konvensi yang sama - jika tidak, manfaat dari keputusan ini tidak akan tercapai.
Namun, seperti yang dicatat oleh poster dalam jawaban SO, nulls mungkin harus dikembalikan jika suatu objek diharapkan sehingga tidak ada keraguan tentang apakah data sedang dikembalikan.
Pada akhirnya, tidak ada satu pun cara terbaik untuk melakukan sesuatu. Membangun konsensus tim pada akhirnya akan mendorong praktik terbaik tim Anda.
sumber
for x in list_of_things() {...}
bisa dibilang lebih cepat untuk grokl = list_of_things(); if l != null {...}
emit(user.hometown)
daripadaif user.hometown == null { emit("") else {emit(user.hometown)}
Di semua kode yang saya tulis, saya menghindari kembali
null
dari suatu fungsi. Saya membacanya di Clean Code .Masalah dengan menggunakan
null
adalah bahwa orang yang menggunakan antarmuka tidak tahu apakahnull
itu hasil yang mungkin, dan apakah mereka harus memeriksanya, karena tidak adanot null
jenis referensi.Di F # Anda dapat mengembalikan
option
tipe, yang bisasome(Person)
ataunone
, jadi jelas bagi pemanggil bahwa mereka harus memeriksa.Pola C # (anti-) analog adalah
Try...
metode:Sekarang aku tahu orang mengatakan mereka membenci satu
Try...
pola karena memiliki parameter output istirahat ide-ide dari fungsi murni, tapi itu benar-benar tidak berbeda dari:... dan jujur Anda dapat mengasumsikan bahwa setiap programmer. NET tahu tentang
Try...
pola karena digunakan secara internal oleh .NET framework. Itu berarti mereka tidak perlu membaca dokumentasi untuk memahami apa yang dilakukannya, yang lebih penting bagi saya daripada berpegang pada pandangan beberapa fungsi purist (memahami ituresult
adalahout
parameter, bukanref
parameter).Jadi saya akan pergi
TryFindPerson
karena Anda tampaknya menunjukkan itu sangat normal untuk tidak dapat menemukannya.Jika, di sisi lain, tidak ada alasan logis bahwa penelepon akan memberikan
personId
yang tidak ada, saya mungkin akan melakukan ini:... dan kemudian saya akan melemparkan pengecualian jika itu tidak valid. The
Get...
awalan menyiratkan bahwa si penelepon tahu itu harus berhasil.sumber
Anda dapat mencoba pola Kasus Khusus Martin Fowler , dari Paterns of Enterprise Application Architecture :
sumber
Saya akan berpikir
ReverseString()
akan mengembalikan string yang terbalik dan itu akan melemparIllegalArgumentException
jika dilewatkan dalamNull
.Saya pikir
FindPerson()
harus mengikuti Pola NullObject atau menaikkan pengecualian yang tidak dicentang tentang tidak menemukan sesuatu jika Anda harus selalu dapat menemukan sesuatu.Harus berurusan
Null
adalah sesuatu yang harus dihindari. MemilikiNull
dalam bahasa telah disebut Kesalahan Miliaran Dolar oleh penemunya!sumber
Kembalikan Opsi . Semua manfaat mengembalikan nilai tidak valid yang berbeda (seperti dapat memiliki nilai kosong di koleksi Anda) tanpa risiko NullPointerException.
sumber
boost::optional<T>
Saya melihat kedua sisi argumen ini, dan saya menyadari beberapa suara yang agak berpengaruh (misalnya, Fowler) menganjurkan tidak mengembalikan nol untuk menjaga kode tetap bersih, menghindari blok penanganan kesalahan tambahan, dll.
Namun, saya cenderung memihak pendukung untuk mengembalikan nol. Saya menemukan ada perbedaan penting dalam memohon suatu metode dan itu menanggapi dengan saya tidak punya data dan menanggapi dengan saya punya String kosong ini .
Karena saya telah melihat beberapa diskusi yang mereferensikan kelas Person, pertimbangkan skenario di mana Anda berusaha mencari instance kelas. Jika Anda memasukkan beberapa atribut finder (mis. ID), klien dapat segera memeriksa nol untuk melihat apakah tidak ada nilai yang ditemukan. Ini tidak selalu luar biasa (karenanya tidak perlu pengecualian), tetapi juga harus didokumentasikan dengan jelas. Ya, ini membutuhkan kekakuan dari pihak klien, dan tidak, saya tidak berpikir itu hal yang buruk sama sekali.
Sekarang pertimbangkan alternatif tempat Anda mengembalikan objek Orang yang valid ... yang tidak memiliki apa-apa di dalamnya. Apakah Anda meletakkan nulls di semua nilainya (nama, alamat, favoriteDrink), atau apakah Anda sekarang mengisi yang dengan objek yang valid tetapi kosong? Bagaimana klien Anda sekarang menentukan bahwa tidak ada Orang yang sebenarnya ditemukan? Apakah mereka perlu memeriksa apakah nama itu adalah String kosong dan bukan null? Bukankah hal semacam ini benar-benar akan menyebabkan sebanyak atau lebih kode kekacauan dan pernyataan kondisional daripada jika kita hanya memeriksa nol dan pindah?
Sekali lagi, ada poin di kedua sisi argumen ini yang bisa saya setujui, tetapi saya menemukan ini paling masuk akal bagi kebanyakan orang (membuat kode lebih dapat dipertahankan).
sumber
FindPerson
atauGetPerson
mengembalikan null atau melemparkan pengecualian jika kunci tidak ada?" Sebagai pengguna API saya tidak tahu dan saya harus memeriksa dokumentasinya. Di sisi lain,bool TryGetPerson(Guid key, out Person person)
tidak mengharuskan saya untuk memeriksa dokumentasi dan saya tahu pengecualian tidak dilemparkan dalam jumlah yang merupakan keadaan yang agak tidak biasa. Itulah poin yang saya coba sampaikan dalam jawaban saya.findPerson
) itu benar-benar normal untuk kembali tanpa hasil. Ini seharusnya tidak mengarah pada pengecualian.Kembalikan nol jika Anda perlu tahu apakah item itu ada atau tidak. Jika tidak, kembalikan tipe data yang diharapkan. Ini terutama benar jika Anda mengembalikan daftar item. Biasanya aman untuk mengasumsikan jika penelepon menginginkan daftar, mereka ingin mengulangi daftar itu. Banyak (kebanyakan? Semua?) Bahasa gagal jika Anda mencoba untuk mengulang lebih dari nol tetapi tidak ketika Anda mengulangi daftar yang kosong.
Saya merasa frustrasi untuk mencoba dan menggunakan kode seperti ini, tetapi gagal:
Saya tidak perlu menambahkan kasus khusus untuk kasus ini ketika tidak ada barang .
sumber
Itu tergantung pada semantik metode. Anda mungkin dapat menentukan, metode Anda hanya menerima "Bukan null". Di Java, Anda dapat menyatakan bahwa menggunakan beberapa penjelasan metadata:
Entah bagaimana Anda harus menentukan nilai kembali. Jika Anda menyatakan, Anda hanya menerima nilai NotNull, Anda terikat untuk mengembalikan string kosong (jika inputnya juga string kosong).
Kasus kedua sedikit rumit dalam semantiknya. Jika metode ini mengembalikan seseorang dengan kunci utama (dan orang tersebut diharapkan ada), cara yang lebih baik adalah dengan melemparkan pengecualian.
Jika Anda mencari orang dengan id tebakan (yang menurut saya aneh), Anda sebaiknya mendeklarasikan metode itu sebagai @Nullable.
sumber
Saya akan merekomendasikan menggunakan pola Obyek Null bila memungkinkan. Ini menyederhanakan kode ketika memanggil metode Anda, dan Anda tidak bisa membaca kode yang jelek
if (someObject != null && someObject.someMethod () != whateverValue)
Misalnya, jika suatu metode mengembalikan koleksi objek yang cocok dengan beberapa pola, maka mengembalikan koleksi kosong lebih masuk akal daripada kembali
null
, dan mengulangi koleksi kosong ini akan hampir tidak ada penalti kinerja. Kasus lain adalah metode yang mengembalikan instance kelas yang digunakan untuk mencatat data, mengembalikan objek Null daripada lebihnull
disukai menurut pendapat saya, karena tidak memaksa pengguna untuk selalu memeriksa apakah referensi yang dikembalikan adalahnull
.Dalam kasus di mana pengembalian
null
masuk akal (memanggilfindPerson ()
metode misalnya), saya akan mencoba setidaknya memberikan metode yang mengembalikan jika objek hadir (personExists (int personId)
misalnya), contoh lain adalahcontainsKey ()
metode pada aMap
di Jawa). Itu membuat kode penelepon lebih bersih, karena Anda dapat dengan mudah melihat bahwa ada kemungkinan bahwa objek yang diinginkan mungkin tidak tersedia (orang tidak ada, kunci tidak ada di peta). Terus-menerus memeriksa apakah suatu referensinull
mengaburkan kode menurut pendapat saya.sumber
null adalah hal terbaik untuk kembali jika dan hanya jika ketentuan berikut ini berlaku:
Selain itu, pastikan bahwa Anda mendokumentasikan fakta bahwa fungsi tersebut dapat mengembalikan nol.
Jika Anda mengikuti aturan ini, nulls sebagian besar tidak berbahaya. Perhatikan bahwa jika Anda lupa untuk memeriksa nol, Anda biasanya akan mendapatkan NullPointerException segera setelah itu, yang biasanya merupakan bug yang cukup mudah untuk diperbaiki. Pendekatan cepat gagal ini jauh lebih baik daripada memiliki nilai balik palsu (mis. String kosong) yang disebarkan secara diam-diam di sekitar sistem Anda, mungkin merusak data, tanpa melemparkan pengecualian.
Akhirnya, jika Anda menerapkan aturan-aturan ini ke dua fungsi yang tercantum dalam pertanyaan:
sumber
Menurut pendapat saya ada perbedaan antara mengembalikan NULL, mengembalikan beberapa hasil kosong (mis. String kosong atau daftar kosong), dan melempar pengecualian.
Saya biasanya mengambil pendekatan berikut. Saya menganggap panggilan fungsi atau metode f (v1, ..., vn) sebagai aplikasi fungsi
di mana S itu "keadaan dunia" T1, ..., Tn adalah jenis parameter input, dan T adalah tipe pengembalian.
Saya pertama kali mencoba mendefinisikan fungsi ini. Jika fungsi ini parsial (yaitu ada beberapa nilai input yang tidak didefinisikan) saya mengembalikan NULL untuk memberi sinyal ini. Ini karena saya ingin penghentian normal dan memberi tahu saya bahwa fungsi yang saya minta tidak didefinisikan pada input yang diberikan. Menggunakan, misalnya, string kosong sebagai nilai kembali bersifat mendua karena bisa jadi fungsi tersebut didefinisikan pada input dan string kosong adalah hasil yang benar.
Saya pikir pemeriksaan tambahan untuk pointer NULL dalam kode panggilan diperlukan karena Anda menerapkan fungsi parsial dan itu adalah tugas dari metode yang dipanggil untuk memberi tahu Anda jika fungsi jika tidak didefinisikan untuk input yang diberikan.
Saya lebih suka menggunakan pengecualian untuk kesalahan yang tidak memungkinkan untuk melakukan perhitungan (yaitu tidak mungkin menemukan jawaban apa pun).
Sebagai contoh, misalkan saya memiliki Pelanggan kelas dan saya ingin menerapkan metode
untuk mencari pelanggan dalam database aplikasi dengan kodenya. Dalam metode ini, saya akan melakukannya
Pemeriksaan tambahan untuk null, misalnya
adalah bagian dari semantik dari apa yang saya lakukan dan saya tidak akan hanya "melewatkannya" untuk membuat kode lebih baik dibaca. Saya tidak berpikir itu adalah praktik yang baik untuk menyederhanakan semantik masalah yang ada hanya untuk menyederhanakan kode.
Tentu saja, karena pemeriksaan untuk null sangat sering terjadi, ada baiknya jika bahasa tersebut mendukung beberapa sintaks khusus untuk itu.
Saya juga akan mempertimbangkan untuk menggunakan pola Objek Null (seperti yang disarankan oleh Laf) selama saya dapat membedakan objek nol kelas dari semua objek lainnya.
sumber
Metode mengembalikan koleksi harus dikembalikan kosong tetapi yang lain bisa mengembalikan nol, karena untuk koleksi itu mungkin terjadi bahwa Anda akan memiliki objek tetapi tidak ada elemen di dalamnya, sehingga penelepon akan memvalidasi untuk ukuran yang adil, bukan keduanya.
sumber
Bagi saya ada dua kasus di sini. Jika Anda mengembalikan semacam daftar, Anda harus selalu mengembalikan daftar itu bagaimanapun caranya, kosongkan jika Anda tidak memiliki apa pun untuk dimasukkan ke dalamnya.
Satu-satunya kasus di mana saya melihat perdebatan adalah ketika Anda mengembalikan satu item. Saya menemukan diri saya lebih memilih untuk mengembalikan nol jika terjadi kegagalan dalam situasi seperti itu atas dasar membuat semuanya gagal dengan cepat.
Jika Anda mengembalikan objek nol dan penelepon membutuhkan objek nyata, mereka mungkin melanjutkan dan mencoba menggunakan objek nol yang menghasilkan perilaku tak terduga. Saya pikir lebih baik bagi rutinitas untuk menjadi booming jika mereka lupa berurusan dengan situasi. Jika ada yang salah, saya ingin pengecualian ASAP. Anda cenderung mengirimkan bug dengan cara ini.
sumber
Menambahkan apa yang sudah dikatakan orang tentang
Maybe
konstruktor tipe:Keuntungan besar lainnya, selain tidak membahayakan NPE, adalah keuntungan semantik. Di dunia fungsional, di mana kita berurusan dengan fungsi murni, kami ingin mencoba membuat fungsi yang ketika diterapkan persis sama dengan nilai pengembaliannya . Pertimbangkan kasus
String.reverse()
: Ini adalah fungsi yang diberikan string tertentu mewakili versi terbalik dari string itu. Kita tahu bahwa string ini ada, karena setiap string dapat dibalik (string pada dasarnya adalah kumpulan karakter yang diatur).Sekarang bagaimana
findCustomer(int id)
? Fungsi ini mewakili pelanggan yang memiliki ID yang diberikan. Ini adalah sesuatu yang mungkin ada atau tidak ada. Tapi ingat, fungsi memiliki nilai pengembalian tunggal, jadi Anda tidak bisa mengatakan "fungsi ini mengembalikan pelanggan dengan ID yang diberikan ATAU mengembalikannull
.Ini adalah masalah utama saya baik dengan mengembalikan
null
dan mengembalikan objek nol. Mereka menyesatkan.null
juga bukan pelanggan, dan juga bukan "tidak adanya pelanggan". Tidak adanya APA SAJA. Ini hanya pointer yang tidak berguna untuk TIDAK ADA. Tingkat sangat rendah dan sangat jelek dan sangat rawan kesalahan. Objek nol juga cukup menyesatkan di sini saya pikir. Pelanggan nol adalah pelanggan. Ini bukan tidak adanya satu, itu bukan pelanggan dengan ID yang diminta, jadi mengembalikannya hanya SALAH. Ini BUKAN pelanggan yang saya minta, tapi tetap saja Anda mengklaim telah mengembalikan pelanggan. Ini memiliki ID yang salah, jelas ini adalah bug. Itu melanggar kontrak yang disarankan oleh nama metode dan tanda tangan. Ini memerlukan kode klien untuk mengasumsikan hal-hal tentang desain Anda, atau membaca dokumentasi.Kedua masalah ini diselesaikan oleh a
Maybe Customer
. Tiba-tiba, kami tidak mengatakan "fungsi ini mewakili pelanggan dengan ID yang diberikan". Kami mengatakan "fungsi ini mewakili pelanggan dengan ID yang diberikan jika ada . Sekarang sangat jelas dan eksplisit tentang apa yang dilakukannya. Jika Anda meminta pelanggan dengan ID yang tidak ada, Anda akan menerimaNothing
. Bagaimana ini lebih baik daripadanull
? Bukan hanya untuk risiko NPE, tetapi juga karena jenisnyaNothing
tidak adilMaybe
. ItuMaybe Customer
memiliki makna semantik. Secara khusus berarti "tidak adanya pelanggan", menunjukkan bahwa pelanggan seperti itu tidak ada.Masalah lain dengan null tentu saja adalah ambigu. Apakah itu karena Anda tidak menemukan pelanggan, atau adakah kesalahan koneksi db atau saya hanya tidak diizinkan untuk melihat pelanggan itu?
Jika Anda memiliki beberapa kasus kesalahan seperti ini untuk ditangani, Anda bisa melempar pengecualian untuk versi tersebut atau (dan saya lebih suka cara ini) Anda bisa mengembalikan
Either CustomerLoadError Customer
, mewakili sesuatu yang salah atau pelanggan yang kembali. Ini memiliki semua kelebihanMaybe Customer
dan juga memungkinkan Anda menentukan apa yang salah.Hal utama yang saya kejar adalah untuk menangkap kontrak fungsi dalam tanda tangan itu. Jangan menganggap hal-hal, jangan mengandalkan konvensi singkat, menjadi eksplisit.
sumber
1) Jika semantik fungsi adalah bahwa ia tidak dapat mengembalikan apa-apa, pemanggil HARUS menguji untuk itu, kalau tidak ia akan misalnya. ambil uangmu dan berikan kepada siapa pun.
2) Ada baiknya membuat fungsi yang secara semantik selalu mengembalikan sesuatu (atau melempar).
Dengan logger , masuk akal untuk mengembalikan logger yang tidak mencatat jika tidak ada logger yang didefinisikan. Saat mengembalikan koleksi, hampir tidak pernah masuk akal (kecuali pada "level cukup rendah", di mana koleksi itu sendiri adalah data, bukan apa yang dikandungnya) untuk tidak mengembalikan apa-apa, karena set kosong adalah set, bukan apa-apa.
Dengan contoh orang , saya akan pergi "hibernate" cara (dapatkan vs load, IIRC, tetapi ada rumit oleh objek proxy untuk pemuatan malas) memiliki dua fungsi, satu yang mengembalikan nol dan yang kedua melempar.
sumber
NULL harus dikembalikan jika aplikasi mengharapkan data tersedia tetapi datanya tidak tersedia. Misalnya, layanan yang mengembalikan CITY berdasarkan kode pos harus mengembalikan nol jika kota tidak ditemukan. Penelepon kemudian dapat memutuskan untuk menangani null atau meledak.
Daftar kosong harus dikembalikan jika ada dua kemungkinan. Data tersedia atau TIDAK ada data. Misalnya layanan yang mengembalikan KOTA jika populasinya lebih besar dari jumlah tertentu. Ini dapat mengembalikan daftar kosong jika Tidak ada data yang memenuhi kriteria yang diberikan.
sumber
Mengembalikan NULL adalah desain yang mengerikan , di dunia berorientasi objek. Singkatnya, penggunaan NULL mengarah ke:
Periksa posting blog ini untuk penjelasan terperinci: http://www.yegor256.com/2014/05/13/why-null-is-bad.html
sumber