Berikut ini ditampilkan kepada semua orang untuk setiap kesalahpahaman.
1. Penggunaan berlebihan NULL
Menghindari penggunaan nol yang berlebihan adalah praktik terbaik. Misalnya, pendekatan yang lebih baik adalah membuat metode kembali ke array atau koleksi kosong alih -alih nilai nol, karena ini dapat mencegah program dari melempar nullpointerException. Fragmen kode berikut akan mendapatkan koleksi dari metode lain:
Daftar <String> AccountIds = person.getAccountIds (); untuk (String AccountId: AccountIds) {ProcessAccount (AccountId);}
Ketika angka tidak memiliki akun, getAccountIds () akan mengembalikan nilai nol, dan program akan membuang pengecualian nullpointerException. Oleh karena itu, perlu untuk bergabung dengan pemeriksaan udara untuk menyelesaikan masalah ini. Jika Anda mengganti nilai null yang dikembalikan dengan daftar kosong, maka NullPointerException tidak akan muncul. Selain itu, karena kita tidak perlu lagi mengikuti pemeriksaan singkat dari variabel AccountID, kode akan menjadi lebih ringkas.
Ketika Anda ingin menghindari nilai nol, skenario yang berbeda dapat mengambil praktik yang berbeda. Salah satu metode adalah menggunakan tipe opsional, yang dapat berupa objek kosong atau paket dari beberapa nilai.
Opsional <string> OptialString = opsional.ofnullable (nulledString);
Faktanya, Java8 memberikan cara yang lebih ringkas:
Opsional <string> optionalString = opsional.ofnullable (nullialString);
Java telah mendukung tipe opsional dari versi Java8, tetapi telah dikenal luas di dunia pemrograman fungsional. Sebelum itu, itu digunakan dalam versi awal Java di Google Guava.
2. Abaikan kelainan
Kita sering mengabaikan kelainan. Namun, praktik terbaik adalah menangani mereka untuk pemula dan pemrogram Java yang berpengalaman. Throwing abnormal biasanya bertujuan, jadi dalam kebanyakan kasus, perlu untuk merekam peristiwa yang menyebabkan kelainan. Jangan meremehkan masalah ini. Setidaknya, untuk memberi tahu pengembang lain, Anda harus menjelaskan mengapa kelainan ini belum ditangani.
Selfie = person.shootelfie ();
Cara sederhana untuk menekankan orang yang tidak penting adalah dengan menggunakan informasi ini sebagai nama variabel yang tidak normal, seperti ini:
Salin kode kode sebagai berikut:
coba {selfie.delete ();} catch (nullpointterexception tidak penting) {}
3. Ubah kelainan secara bersamaan
Kelainan ini terjadi pada objek pengumpulan, dan pada saat yang sama tidak menggunakan metode yang disediakan oleh objek Iterator untuk memperbarui konten dalam koleksi. Misalnya, ada daftar topi di sini, dan Anda ingin menghapus semua nilai yang berisi flap telinga:
Daftar <Ihats = ArrayList baru <> (); HASEARFLAPS ()) {Hats.Remove (Hat);}}
Jika kode ini berjalan, ConcurrentModificationException akan dilemparkan, karena kode akan memodifikasinya saat melintasi koleksi ini. Ketika beberapa proses bertindak pada daftar yang sama, ketika salah satu proses melintasi daftar, proses lainnya mencoba memodifikasi konten daftar, dan kelainan yang sama juga dapat terjadi.
Ini sangat umum dalam konten koleksi modifikasi konread multi -beracun, sehingga perlu menggunakan metode yang biasa digunakan dalam pemrograman bersamaan, seperti kunci sinkron, set khusus untuk modifikasi bersamaan, dan sebagainya. Java memecahkan masalah ini dalam satu utas dan situasi multi -utara.
Kumpulkan benda dan hapus dalam siklus lain
Solusi langsungnya adalah memasukkan topi dengan flap telinga ke dalam daftar, dan kemudian menghapusnya dengan siklus lain. Namun, ini membutuhkan satu set tambahan untuk menyimpan topi untuk dihapus.
Daftar <hatstoreMove = LinkedList baru <> ();
Gunakan metode iterator.remove
Metode ini lebih sederhana, dan pada saat yang sama tidak perlu membuat koleksi tambahan:
Iterator <hatitrator = hats.iterator ();
Metode menggunakan ListIterator
Ketika kumpulan koleksi antarmuka daftar diimplementasikan, daftar iterator adalah pilihan yang sangat cocok. Iterator yang mengimplementasikan antarmuka Listoration tidak hanya mendukung operasi penghapusan, tetapi juga mendukung operasi Tambah dan Tetapkan. Antarmuka Listotrator mengimplementasikan antarmuka Iterator, jadi contoh ini terlihat mirip dengan metode hapus iterator. Satu -satunya perbedaan adalah jenis topi iterator dan kami memperoleh metode iterator -menggunakan metode listotrator (). Fragmen -fragmen berikut menunjukkan cara menggunakan metode listterator.remove dan listotrator.add untuk mengganti topi flap telinga dengan som <ombreros.
Ihat Sombrero = new Sombrero (); ;
Menggunakan ListIterator, Memanggil Hapus dan Tambah Metode dapat diganti untuk memanggil hanya satu metode set:
Ihat Sombrero = new Sombrero (); ); // atur alih -alih hapus dan tambahkan}}}
Gunakan metode stream di Java 8
Di Java8, pengembang dapat mengubah koleksi menjadi aliran dan menyaring aliran sesuai dengan beberapa kondisi. Contoh ini menceritakan bagaimana topi filter API Stream dan menghindari ConcurrentModificationException. Hats = Hats.stream ().
Salin kode kode sebagai berikut:
.Collect (collector.tocollection (arraylist :: new));
Metode Collectors.tocollection akan membuat daftar array baru, yang bertanggung jawab untuk menyimpan nilai topi yang difilter. Jika kondisi penyaringan disaring sejumlah besar entri, daftar array besar akan dihasilkan di sini. Karena itu, Anda perlu menggunakannya dengan hati -hati.
Gunakan Metode List.Removeif di Java 8
Anda dapat menggunakan metode lain yang lebih ringkas dan jelas dalam metode Java 8 -removeif:
Salin kode kode sebagai berikut:
Hats.removeif (ihat :: hASearflaps);
Di bagian bawah, ia menggunakan iterator.remove untuk menyelesaikan operasi ini.
Gunakan koleksi khusus
Jika Anda memutuskan untuk menggunakan CopyOnWriteArrayList alih -alih ArrayList di awal, tidak akan ada masalah. Karena CopyOnWriteArrayList menyediakan metode yang dimodifikasi (seperti SET, ADD, REMPERLALU), itu tidak akan mengubah array koleksi asli, tetapi membuat versi yang dimodifikasi baru. Ini memungkinkan Traversal untuk memodifikasi versi asli, sehingga ConcurrentModificationException tidak dibuang. Kerugian dari koleksi ini juga sangat jelas -koleksi baru dihasilkan untuk setiap modifikasi.
Ada set lain yang cocok untuk skenario yang berbeda, seperti CopyonWriteSet dan ConcurrenthashMap.
Mengenai kesalahan lain yang mungkin terjadi selama modifikasi bersamaan, itu menciptakan aliran dari koleksi. Kriteria umum untuk stream adalah untuk menghindari memodifikasi koleksi back -end saat memeriksa aliran. Contoh selanjutnya akan menunjukkan cara menangani aliran dengan benar:
Daftar <ihat> filedhats = hats.stream ().
Metode Peek mengumpulkan semua elemen dan melakukan tindakan yang ditetapkan untuk setiap elemen. Di sini, tindakannya adalah mencoba menghapus data dari daftar dasar, yang jelas salah. Untuk menghindari operasi seperti itu, Anda dapat mencoba beberapa metode yang dijelaskan di atas.
4. Pertahanan
Kadang -kadang, untuk berkolaborasi dengan lebih baik, kode yang disediakan oleh perpustakaan standar atau pihak ketiga harus mematuhi dependensi umum. Misalnya, perlu untuk mematuhi perjanjian bersama antara kode hash dan sama untuk memastikan bahwa serangkaian kelas koleksi dalam kerangka kerja koleksi Java dan kelas -kelas lain menggunakan kode hashcode dan sama dengan metode dapat bekerja secara normal. Jangan mematuhi kesalahan seperti pengecualian atau menghancurkan kompilasi kode;
Kode kesalahan mungkin menyelinap ke lingkungan produksi, menyebabkan banyak efek samping. Ini termasuk pengalaman UI yang buruk, laporan data yang salah, kinerja aplikasi yang buruk, kehilangan data atau lebih. Untungnya, kesalahan bencana ini tidak sering terjadi. Kode hash dan setara telah disebutkan sebelumnya bahwa adegan yang muncul mungkin: koleksi tergantung pada target untuk membandingkan objek atau perbandingan, seperti hashmap dan hashset. Secara sederhana, ada dua kriteria untuk perjanjian ini:
Jika kedua objek itu sama, maka kode hash harus sama.
Jika kedua objek memiliki kode hash yang sama, mereka mungkin sama atau berbeda.
Kriteria pertama untuk kehancuran, ketika Anda mencoba mengambil data dari hashmap, itu akan menyebabkan kesalahan. Kriteria kedua berarti bahwa objek dengan kode hash yang sama tidak harus sama.
Mari kita lihat konsekuensi dari menghancurkan kriteria pertama:
Public Static Class Boat {Private String Name; getClass ()! int hashcode () {return (int) (math.random () * 5000);}}
Seperti yang Anda lihat, kelas kapal menulis ulang metode kode yang setara dan hashcode. Namun, itu menghancurkan perjanjian karena kode hash mengembalikan nilai acak untuk objek yang sama untuk setiap panggilan. Kode berikut kemungkinan tidak akan menemukan kapal yang disebut Enterprise in Hashset, meskipun sebenarnya kami telah menambahkan jenis kapal ini sebelumnya:
Public static void main (string [] args) {set <hoat> boats = hashset baru <> (); (Perahu baru ("perusahaan"));};}
Perjanjian lain adalah metode finalisasi. Berikut adalah referensi ke dokumen Java resmi tentang deskripsi fungsionalnya:
Perjanjian konvensional Finalisasi adalah: Ketika mesin virtual JavatM menentukan bahwa utas apa pun tidak dapat lagi mengakses objek yang ditentukan dengan cara apa pun, metode ini akan dipanggil. Metode finalisasi memiliki banyak fungsi, termasuk penggunaan objek ini untuk tersedia lagi untuk utas lain; Misalnya, metode finalisasi yang menunjukkan objek koneksi input/output dapat menjalankan transaksi I/O eksplisit untuk mengganggu koneksi sebelum objek yang dibuang permanen.
Anda dapat memutuskan untuk menggunakan metode finalisasi dalam prosesor file untuk melepaskan sumber daya, tetapi penggunaan ini buruk. Karena itu dipanggil selama daur ulang sampah dan waktu GC tidak yakin, waktu untuk finalisasi tidak akan dijamin.
5. Gunakan tipe asli alih -alih parameterisasi
Menurut Dokumen Java Deskripsi: Tipe asli adalah non -parameterized, atau anggota RM non -statis (juga non -warisan R induk atau antarmuka induk). Sebelum jenis generik Java diperkenalkan, tidak ada jenis alternatif primitif. Java telah mendukung pemrograman generik dari versi 1.5, dan tidak ada keraguan bahwa ini adalah peningkatan fungsi yang penting. Namun, karena kompatibilitas ke belakang, ada jebakan di sini yang dapat menghancurkan seluruh sistem jenis. Berusahalah contohnya:
ListOfNumbers = ArrayList baru ();
Ini adalah daftar angka yang didefinisikan sebagai arraylist asli. Karena tidak menentukan parameter tipe, ia dapat menambahkan objek apa pun ke dalamnya. Namun, baris terakhir memetakan elemen yang dikandungnya untuk tipe int dan dikalikan dengan 2, mencetak data setelah menggandakan data ke output standar.
Kode ini tidak akan membuat kesalahan selama kompilasi, tetapi begitu berjalan, ia akan melempar kesalahan saat berjalan, karena mencoba memetakan jenis karakter ke operasi plastik. Jelas, jika informasi yang diperlukan disembunyikan, sistem tipe tidak akan membantu menulis kode keamanan.
Untuk mengatasi masalah ini, Anda perlu menentukan jenis spesifik untuk objek dalam koleksi:
Daftar <Integer> ListOfNumbers = ArrayList baru <() ();
Satu -satunya perbedaan dari kode sebelumnya adalah baris yang mendefinisikan koleksi:
Salin kode kode sebagai berikut:
Daftar <Integer> listOfnumbers = new ArrayList <();
Kompilasi kode yang dimodifikasi tidak dapat dilewati karena mencoba menambahkan string ke pengumpulan plastik penyimpanan yang diharapkan. Kompiler akan menampilkan pesan kesalahan dan menunjuk ke baris yang menambahkan dua puluh karakter ke daftar. Parameterisasi Jenis generik adalah ide yang bagus. Dalam hal ini, kompiler dapat memeriksa jenis yang mungkin, sehingga peluang abnormal runtime karena ketidakkonsistenan akan sangat berkurang.
Ringkasan utama dari lima programmer Java di atas sering membuat kesalahan, saya harap semua orang bisa menyukainya.