Mengapa java.util.ArrayList mengizinkan untuk menambahkan nol?

41

Saya bertanya-tanya mengapa java.util.ArrayListmemungkinkan untuk menambahkan null. Apakah ada kasus di mana saya ingin menambahkan nullke ArrayList?

Saya mengajukan pertanyaan ini karena dalam sebuah proyek kami memiliki bug di mana beberapa kode ditambahkan nullke ArrayListdan sulit untuk menemukan di mana bug itu. Jelas sebuah NullPointerExceptiondilemparkan tetapi tidak sampai kode lain mencoba mengakses elemen. Masalahnya adalah bagaimana menemukan kode yang menambahkan nullobjek. Akan lebih mudah jika ArrayListmelemparkan pengecualian dalam kode tempat elemen ditambahkan.

Alfredo Osorio
sumber
12
The Jambu Project memiliki halaman yang cukup menarik tentang topik yang (mereka tidak mengizinkan nulldi sebagian besar koleksi mereka).
Joachim Sauer
6
Saya percaya bahwa jawaban yang diberikan di sini mencakup pertanyaan dengan baik. Mungkin satu hal yang harus disebutkan adalah: jangan menganggap semua yang ada di JDK sebagai holly dan sempurna, dan kemudian memukul kepala Anda mencoba memahami mengapa itu begitu "sempurna". Beberapa hal adalah kesalahan (jujur, IMHO), yang tetap ada karena kompatibilitas ke belakang dan hanya itu. Bahkan para pembuat Java mengakuinya, baca saja buku-buku Joshua Bloch untuk melihat kritiknya terhadap Java API tertentu. Bagaimanapun, pertanyaan Anda turun ke cuaca tidak ada cara yang lebih elegan untuk menangkap NPE di Jawa. Jawabannya adalah, tidak, tetapi harus ada.
Shivan Dragon
2
Bisakah Anda memberikan informasi lebih lanjut mengapa itu tidak boleh? Jika itu hanya masalah selera, maka yang kurang ketat harus lebih disukai.
Mare Infinitus
Jawaban sederhananya hanyalah itu nulladalah cara default untuk mewakili data yang hilang di Jawa, apakah Anda suka atau tidak. Bahkan banyak orang tidak menyukainya dan menjadikannya argumen untuk hal-hal gaya pemrograman fungsional. Jawaban yang paling banyak dipilih tidak masuk akal / tidak menangkap esensi masalah.
xji
@ JIXiang Kamu terlalu menyederhanakan apa nullitu. "Hilang" hanyalah salah satu dari beberapa interpretasi potensial null. Interpretasi lain yang valid dapat berupa "Tidak Diketahui," "Tidak Berlaku," atau "Tidak diinisialisasi." Apa yang nulldiwakili tergantung pada aplikasi. Seperti yang akan dikatakan komunitas Python, "Di hadapan ambiguitas, tolak godaan untuk menebak." Menolak memegang nol dalam wadah yang benar-benar mampu melakukannya hanya akan menjadi - sebuah tebakan.
riwalk

Jawaban:

34

Keputusan desain ini muncul sebagian besar didorong oleh penamaan.

Nama ArrayList menyarankan kepada pembaca fungsi yang mirip dengan array - dan wajar bagi para desainer Java Collections Framework untuk berharap bahwa sebagian besar pengguna API akan bergantung pada fungsinya yang mirip dengan array.

Ini khususnya, melibatkan perawatan elemen-elemen nol. Pengguna API mengetahui bahwa di bawah ini berfungsi OK:

array[0] = null; // NPE won't happen here

akan sangat terkejut mengetahui apakah kode yang sama untuk ArrayList akan membuang NPE:

arrayList.set(0, null); // NPE => WTF?

Penalaran seperti di atas disajikan dalam JCF tutorial menekankan poin yang menunjukkan kesamaan antara ArrayList dan array sederhana:

ArrayList ... menawarkan akses posisi waktu konstan dan cepat ...

Jika Anda ingin implementasi Daftar yang melarang nol, lebih baik disebut seperti NonNullableArrayListatau sesuatu seperti itu, untuk menghindari pengguna API yang membingungkan.


Catatan tambahan ada diskusi tambahan dalam komentar di bawah ini, bersama dengan pertimbangan tambahan yang mendukung alasan yang disebutkan di sini.

agas
sumber
12
Penjelasan ini tidak meyakinkan, mengingat LinkedList juga mendukung nullentri daftar.
Stephen C
12
Ya ... tapi penjelasan yang lebih sederhana dan (IMO) lebih masuk akal adalah bahwa mengizinkan nullentri berguna dalam banyak kasus.
Stephen C
7
ArrayList tidak dipanggil seperti itu karena meniru array. Disebut seperti itu karena ini adalah daftar yang diimplementasikan sebagai array. Sama seperti TreeMap tidak berperilaku seperti Pohon.
Florian F
11
Jawaban ini, IMO, benar-benar salah. Null diperbolehkan karena di Jawa, baik atau buruk, (IMO, lebih buruk) null digunakan banyak untuk mewakili nilai yang tidak diinisialisasi atau hilang. Bagaimana cara mendapatkan suara terbanyak dan cek "terima"? Serius, saya benar-benar kehilangan kepercayaan pada StackOverflow hari ini.
user949300
8
Jawaban ini jelas salah. Ini hanya dugaan yang tidak didukung tentang nol yang diizinkan dalam implementasi daftar. Berikut adalah Roundup dari koleksi Java memungkinkan / nulls pelarangan; perhatikan bagaimana itu tidak ada hubungannya dengan kemiripan dengan array.
Andres F.
32

Null mungkin nilai yang valid untuk elemen daftar. Katakanlah daftar Anda mengandung elemen yang mewakili beberapa data opsional tentang daftar pengguna dan disimpan dalam urutan yang sama dengan pengguna. Jika data tambahan diisi maka daftar Anda akan berisi data tambahan jika tidak, slot yang terkait dengan pengguna akan menjadi nol. (Saya yakin ada contoh yang lebih baik, tetapi Anda mendapatkan idenya)

jika Anda tidak ingin memperbolehkan nulls ditambahkan maka Anda bisa membungkus daftar array dengan pembungkus Anda sendiri yang dilemparkan ketika nol ditambahkan.

Sam Holder
sumber
2
Itu tampak seperti contoh buruk mengapa nol harus diizinkan - ada cara yang lebih baik untuk merepresentasikan data opsional daripada menggunakan nilai nol dalam daftar.
casablanca
@casablanca ya sepenuhnya setuju, ini bukan contoh yang bagus.
Sam Holder
Saya tidak dapat menemukan alasan yang bagus untuk ArrayList mengandung nulls, selain kejutan buruk bagi pengembang berikutnya untuk 'menemukannya': /
AndreasScheinert
7
@casablanca Sementara saya setuju dengan Anda bahwa nulls harus dihindari untuk mewakili data opsional, di Jawa, baik atau buruk, itu "tradisional".
user949300
2
Casing penggunaan yang solid: Anda ingin meneruskan parameter ke beberapa fungsi dinamis sebagai daftar. Anda memiliki beberapa fungsi, masing-masing dengan set parameter yang berbeda, sehingga Anda memerlukan array berukuran dinamis dan Anda selalu dapat melewatkan null sebagai argumen fungsi yang valid!
Falco
19

ArrayListmemungkinkan null dengan desain. Disengaja. Dari javadoc :

"[ArrayList adalah] implementasi array-resizable dari antarmuka Daftar. Menerapkan semua operasi daftar opsional, dan mengizinkan semua elemen, termasuk nol ."

Jawaban untuk "mengapa" adalah bahwa jika bukan ArrayList tidak akan dapat digunakan dalam kasus-kasus di mana perlu untuk memasukkan nulldalam daftar. Sebaliknya, Anda dapat mencegah ArrayList berisi null dengan menguji nilai sebelum menambahkannya atau menggunakan pembungkus yang mencegah hal ini terjadi.

Apakah ada kasus di mana saya ingin menambahkan null ke ArrayList?

Jelas, kasus mana pun nullmemiliki makna yang berbeda. Misalnya itu mungkin berarti bahwa nilai pada posisi tertentu dalam daftar belum diinisialisasi atau disediakan.

Akan lebih mudah jika ArrayList telah melemparkan pengecualian dalam kode tempat elemen ditambahkan.

Anda bisa dengan mudah menerapkan perilaku itu dengan membuat kelas pembungkus. Namun, ini bukan perilaku yang paling dibutuhkan oleh programmer / aplikasi.

Stephen C
sumber
8

Apakah ada kasus di mana saya ingin menambahkan null ke ArrayList?

Tentu, bagaimana dengan pra-alokasi? Anda menginginkan beberapa ArrayListhal yang belum dapat Anda buat karena Anda tidak memiliki cukup info. Hanya karena Anda tidak dapat memikirkan alasan mengapa seseorang mungkin ingin melakukan sesuatu tidak menjadikannya ide yang buruk. Terserah. (Sekarang, saya yakin seseorang akan datang dan mengatakan Anda seharusnya memiliki benda kosong yang memenuhi beberapa pola yang mereka baca di beberapa blog yang tidak jelas dan bahwa programmer harus benar-benar dapat menulis program tanpa menggunakan ifpernyataan, bla bla.)

Jika kalian memiliki kontrak yang tidak boleh ada nulldalam wadah maka terserah Anda untuk memastikan bahwa kontrak ditegakkan, mungkin paling tepat dengan menegaskan. Mungkin akan membawa Anda maksimal 10 baris kode. Java membuatnya sangat mudah bagi Anda untuk melakukan hal semacam ini. JDK tidak dapat membaca pikiran Anda.

James
sumber
1
Argumen pra-alokasi Anda tidak valid, karena ini sudah membangun ke dalam ArrayList dengan ensureCapacity(int minCapacity)metode dan ArrayList(int initialCapacity)konstruktor.
Philipp
7
@ Pilhipp Nilai apa yang akan dimasukkan ke ruang itu?
James
Pilihan yang jelas adalah memasukkan a nulldalam entri yang telah dialokasikan sebelumnya (tetapi belum digunakan ) ArrayList; tetapi kita dapat membiarkannya tetapi ensureCapacitytidak mengizinkan fungsi lain seperti setmelakukannya. Alasan yang diberikan di tempat lain tampak lebih kuat.
David K
@ Davidvid: Masuk akal untuk mengatakan bahwa itu harus mungkin untuk setsuatu barang dengan nilai berapa pun yang dapat dikembalikan get. Sekalipun upaya normal terhadap getitem yang telah dialokasikan ruang tetapi tidak pernah ditulis harus membuang pengecualian daripada kembali null, masih akan berguna untuk memiliki sepasang metode yang akan memungkinkan list1.setOrEraseIfNull(index, list2.getOrReturnNull(index))daripada membutuhkanif (list2.valueSet(index)) list1.set(index, list2.get(index)); else list1.unset(index);
supercat
1
@ Davidvid: Mencoba untuk membaca entri yang telah dialokasikan tetapi belum ditulis harus menghasilkan nol atau melemparkan pengecualian; lebih mudah untuk mengembalikannya nol.
supercat
4

Ini sepertinya lebih merupakan pertanyaan filosofis (perangkat lunak) di sini.

ArrayList sebagai kelas utilitas dirancang untuk membantu dalam konteks yang luas dari kasus penggunaan yang mungkin.

Bertentangan dengan klaim tersembunyi Anda bahwa menerima nol sebagai nilai yang valid harus dihilangkan, ada banyak contoh di mana nilai nol itu sah menurut hukum.

Alasan paling penting adalah bahwa nullini do not knowsetara dengan semua jenis referensi, termasuk jenis kerangka kerja. Ini menyiratkan bahwa null tidak dapat diganti dalam hal apa pun dengan versi nothingnilai yang lebih lancar .

Jadi, katakanlah Anda menyimpan Integer 1, 3, 7 di daftar array Anda pada indeks yang sesuai: Karena beberapa perhitungan, Anda ingin mendapatkan elemen pada indeks 5, jadi yang harus dikembalikan oleh array Anda adalah: "tidak ada nilai yang disimpan". Ini dapat dicapai melalui pengembalian null atau NullObject . Dalam kebanyakan kasus mengembalikan nilai null bawaan cukup ekspresif. Setelah memanggil metode yang dapat mengembalikan nol dan menggunakan nilai baliknya, cek nilai yang dikembalikan terhadap nol cukup umum dalam kode modern.

Mare Infinitus
sumber
4

Pernyataan

File f = null;

valid dan bermanfaat (saya pikir saya tidak perlu menjelaskan alasannya). Juga bermanfaat untuk memiliki koleksi file, beberapa di antaranya mungkin nol.

List<File> files = new ArrayList<File>();
// use my collection of files
// ....
// not using this one anymore:
files.set(3, null);

Kegunaan koleksi yang mungkin berisi objek nol hasil langsung dari kegunaan objek yang mungkin nol. Ini sangat sederhana.

kode-x
sumber
2

Lebih mudah menerima semuanya, daripada menjadi membatasi dan kemudian mencoba membuka desain Anda setelah fakta.

Sebagai contoh, bagaimana jika mereka oracle / sun hanya menyediakan NonNullableArrayList, tetapi Anda ingin dapat menambahkan Null ke daftar Anda. Bagaimana Anda melakukannya? Anda mungkin harus membuat objek yang sama sekali berbeda, Anda tidak dapat menggunakan memperpanjang NonNullableArrayList. Alih-alih jika Anda memiliki ArrayList yang mengambil semuanya, Anda dapat dengan mudah memperluasnya, dan mengganti add, di mana ia tidak menerima nilai nol.

NiteRain
sumber
2
Tidak setuju. Membiarkan terlalu banyak sulit untuk dikoreksi begitu kesalahan telah melihat penggunaan luas. Jika perancang bahasa mengizinkan nol pada tahap berikutnya, itu tidak akan merusak program yang ada, tetapi yang sebaliknya tidak benar.
Andres F.
2
Tapi saya setuju. Ini tentang memaksimalkan fungsionalitas. Anda dapat menggunakan daftar yang menerima nol bahkan jika Anda tidak membutuhkannya. Anda tidak dapat menggunakan daftar yang menolak nol jika Anda membutuhkan nol.
Florian F
-1

Kegunaan nol?

Sangat banyak ketika Anda pergi dengan Daftar Daftar untuk memodelkan pelat kehidupan nyata 2D dengan posisi yang berbeda. Setengah dari posisi itu bisa kosong (dalam koordinat acak) sementara yang diisi tidak mewakili int atau String sederhana tetapi diwakili oleh objek yang kompleks. Jika Anda ingin menyimpan informasi posisi, Anda perlu mengisi tempat kosong dengan nol sehingga list.get (x) .get (y)tidak menyebabkan kejutan yang tidak menyenangkan. Untuk melawan pengecualian nol Anda dapat memeriksa null (sangat populer) atau Anda dapat menggunakan Opsional (yang menurut saya berguna dalam kasus ini). Alternatifnya adalah mengisi tempat-tempat kosong dengan benda-benda "sampah" yang dapat menyebabkan semua jenis kekacauan di jalan. Jika cek nol Anda gagal atau dilupakan di suatu tempat, Java akan memberi tahu Anda. Di sisi lain objek placeholder "sampah" yang tidak diperiksa dengan benar dapat melewati tanpa disadari.

Nanobody
sumber