Kata pengantar
Saya merevisinya pada Maret 2016 dan meninjau kembali mengapa saya perlu mengoptimalkan kode berdasarkan pekerjaan saya sendiri dan pengalaman belajar harian saya. Sebelum saya diubah, pernyataan saya seperti ini:
Sama seperti ikan paus makan udang, mungkin makan satu atau dua udang tidak terlalu efektif untuk paus, tetapi jika Anda makan terlalu banyak udang, paus akan penuh. Optimalisasi kode adalah sama. Mungkin satu atau dua optimisasi tidak penting untuk meningkatkan efisiensi kode yang berjalan, tetapi selama Anda dapat memperhatikan optimasi kode di mana -mana, umumnya sangat berguna untuk meningkatkan efisiensi kode yang berjalan.
Tampilan ini, dalam tampilan ini, adalah alasan untuk optimasi kode, tetapi tidak sepenuhnya benar. Saat ini, dengan pengembangan teknologi mekanis, server sering memiliki 8 core, 16 core, dan CPU 64-bit, dan efisiensi eksekusi kode sangat tinggi. StringBuilder menggantikan StringBuffer dan ArrayList menggantikan Vector, yang meningkatkan efisiensi operasi kode dengan sangat kecil. Bahkan jika Anda melihat setiap poin dalam proyek, Anda tidak dapat melihat perubahan yang jelas dalam operasi kode.
Saya pikir peran terpenting dari optimasi kode adalah: untuk menghindari kesalahan yang tidak diketahui. Selama kode yang berjalan online, banyak kesalahan tak terduga sering terjadi, karena lingkungan online dan lingkungan pengembangan sangat berbeda, dan penentuan posisi kesalahan seringkali merupakan alasan yang sangat kecil. Namun, untuk menyelesaikan kesalahan ini, kita harus memverifikasi diri terlebih dahulu, kemudian mengemas file kelas untuk diganti, menangguhkan bisnis dan memulai kembali. Untuk proyek yang matang, yang terakhir sebenarnya memiliki dampak yang sangat besar, yang berarti bahwa pengguna tidak dapat mengakses aplikasi selama periode ini. Oleh karena itu, saat menulis kode, memperhatikan berbagai detail dari sumber, menimbang dan menggunakan pilihan terbaik akan sangat menghindari kesalahan yang tidak diketahui dan sangat mengurangi beban kerja dalam jangka panjang.
Tujuan optimasi kode adalah:
1. Kurangi volume kode
2. Tingkatkan efisiensi operasi kode
Beberapa isi artikel ini berasal dari internet, dan beberapa berasal dari pekerjaan dan belajar sehari -hari. Tentu saja, ini tidak penting. Yang penting adalah apakah rincian optimasi kode ini benar -benar berguna. Kemudian artikel ini akan diperbarui untuk waktu yang lama. Selama Anda menemukan detail optimasi kode yang layak dibagikan, artikel ini akan diperbarui dari waktu ke waktu.
Detail Optimasi Kode
(1) Cobalah untuk menentukan pengubah akhir kelas dan metode sebanyak mungkin
Kelas dengan pengubah akhir tidak dapat diturunkan. Di Java Core API, ada banyak contoh menerapkan final, seperti java.lang.string, dan seluruh kelas adalah final. Menentukan pengubah akhir untuk suatu kelas dapat mencegah kelas diwarisi, dan menentukan pengubah akhir untuk suatu metode dapat mencegah metode tersebut menjadi ditimpa. Jika kelas ditentukan sebagai final, semua metode kelas itu bersifat final. Kompiler Java akan mencari peluang untuk melapisi semua metode terakhir. Inline sangat penting untuk meningkatkan efisiensi berjalan Java. Untuk detailnya, lihat Optimasi Java Runtime. Langkah ini dapat meningkatkan kinerja dengan rata -rata 50%.
(2) Cobalah untuk menggunakan kembali objek
Khusus untuk penggunaan objek string, StringBuilder/StringBuffer harus digunakan sebagai gantinya ketika gabungan string terjadi. Karena mesin virtual Java tidak hanya perlu menghabiskan waktu menghasilkan objek, mereka mungkin juga perlu menghabiskan waktu pengumpulan sampah dan memproses objek -objek ini di masa depan, menghasilkan terlalu banyak objek akan memiliki dampak besar pada kinerja program.
(3) Gunakan variabel lokal sebanyak mungkin
Parameter berlalu saat memanggil metode dan variabel sementara yang dibuat dalam panggilan disimpan di tumpukan, yang lebih cepat. Variabel lain, seperti variabel statis, variabel instance, dll., Semuanya dibuat di tumpukan, yang lebih lambat. Selain itu, karena variabel yang dibuat dalam tumpukan selesai, konten ini hilang dan tidak diperlukan pengumpulan sampah tambahan.
(4) Tutup aliran dalam waktu
Selama pemrograman Java, berhati -hatilah saat melakukan koneksi basis data dan operasi streaming I/O. Setelah digunakan, tutup tepat waktu untuk melepaskan sumber daya. Karena pengoperasian benda -benda besar ini akan menyebabkan overhead sistem besar, dan jika Anda tidak hati -hati, itu akan menyebabkan konsekuensi serius.
(5) Minimalkan perhitungan variabel berulang
Untuk mengklarifikasi konsep, bahkan jika hanya ada satu kalimat dalam metode ini, masih dikonsumsi, termasuk membuat bingkai tumpukan, melindungi situs saat memanggil metode, dan memulihkan situs saat memanggil metode tersebut. Jadi misalnya, operasi berikut:
untuk (int i = 0; i <list.size (); i ++) {...}Disarankan untuk menggantinya dengan:
untuk (int i = 0, length = list.size (); i <length; i ++) {...}Dengan cara ini, ketika list.size () sangat besar, ini mengurangi banyak konsumsi
(6) Cobalah untuk mengadopsi strategi pemuatan malas, yaitu, buat saat dibutuhkan
Misalnya:
String str = "aaa"; if (i == 1) {list.add (str);}Disarankan untuk menggantinya dengan:
if (i == 1) {string str = "aaa"; list.add (str);}(7) Gunakan kelainan dengan hati -hati
Kelainan tidak baik untuk kinerja. Untuk melempar pengecualian, Anda harus terlebih dahulu membuat objek baru. Konstruktor antarmuka yang dapat dilempar memanggil metode sinkronisasi lokal bernama FillInstackTrace (). Metode FillInstackTrace () memeriksa tumpukan dan mengumpulkan informasi jejak panggilan. Selama pengecualian dilemparkan, mesin virtual Java harus menyesuaikan tumpukan panggilan karena objek baru dibuat selama pemrosesan. Pengecualian hanya dapat digunakan untuk penanganan kesalahan dan tidak boleh digunakan untuk mengontrol aliran program.
(8) Jangan gunakan coba ... tangkap ... di loop, itu harus ditempatkan di lapisan terluar
Menurut pendapat yang diajukan oleh netizens, saya pikir ini layak dibahas
(9) Jika panjang konten yang akan ditambahkan dapat diperkirakan, tentukan panjang awal untuk kelas pengumpulan dan alat yang diimplementasikan dalam array pada lapisan yang mendasarinya.
Misalnya, ArrayList, Linkedllist, StringBuilder, StringBuffer, HashMap, Hashset, dll. Ambil StringBuilder sebagai contoh:
StringBuilder () // Default Alokasikan 16 Karakter Space StringBuilder (ukuran int) // Default Alokasikan 16 Karakter Space StringBuilder (String Str) // Allokat Default 16 Karakter + Str.Length () Ruang Karakter
Kapasitas inisialisasi dapat ditetapkan melalui konstruktor kelas (di sini kita merujuk tidak hanya ke stringbuilder di atas), yang secara signifikan dapat meningkatkan kinerja. Misalnya, StringBuilder, panjang mewakili jumlah karakter yang dapat dipertahankan oleh StringBuilder saat ini. Karena ketika StringBuilder mencapai kapasitas maksimumnya, ia akan meningkatkan kapasitasnya sendiri menjadi 2 kali dan menambahkan 2. Setiap kali StringBuilder mencapai kapasitas maksimumnya, ia harus membuat array karakter baru dan menyalin konten array karakter lama ke array karakter baru - ini adalah operasi yang sangat memakan kinerja. Bayangkan saja, jika Anda dapat memperkirakan bahwa 5000 karakter disimpan dalam array karakter tanpa menentukan panjangnya, kekuatan 2 terdekat dengan 5000 adalah 4096, dan 2 ditambahkan ke setiap ekspansi terlepas dari 2, lalu: lalu:
Berdasarkan 4096, berlaku untuk array karakter berukuran 8194, yang menambah susunan karakter berukuran 12290 sekaligus. Jika Anda dapat menentukan array karakter berukuran 5000 di awal, Anda akan menghemat lebih dari dua kali ruang untuk menyalin karakter 4096 asli ke dalam array karakter baru.
Ini tidak hanya membuang -buang ruang memori tetapi juga mengurangi efisiensi operasi kode. Oleh karena itu, tidak salah untuk menetapkan kapasitas inisialisasi yang masuk akal untuk kelas pengumpulan dan alat yang diterapkan dalam array yang mendasarinya, yang akan membawa hasil langsung. Namun, perhatikan bahwa koleksi seperti hashmap yang diimplementasikan dalam array + daftar tertaut tidak boleh mengatur ukuran awal sama dengan ukuran perkiraan Anda, karena kemungkinan hanya satu objek yang terhubung ke tabel hampir 0. Disarankan untuk menetapkan ukuran awal ke N.
(10) Saat menyalin sejumlah besar data, gunakan perintah System.ArrayCopy ()
(11) Penggandaan dan Divisi Gunakan Operasi Shift
Misalnya:
untuk (val = 0; val <100000; val += 5) {a = val * 8; b = val / 2;}Menggunakan operasi shift dapat sangat meningkatkan kinerja, karena di bagian bawah komputer, operasi penentuan posisi adalah yang paling nyaman dan tercepat, sehingga disarankan untuk memodifikasinya menjadi:
untuk (val = 0; val <100000; val += 5) {a = val << 3; b = val >> 1;}Meskipun operasi shift cepat, mungkin membuat kode sulit dipahami, jadi yang terbaik adalah menambahkan komentar yang sesuai.
(12) Jangan terus -menerus membuat referensi objek di loop
Misalnya:
untuk (int i = 1; i <= count; i ++) {objek obj = objek baru (); }Pendekatan ini akan menyebabkan referensi objek objek hitungan ada di memori. Jika jumlahnya besar, itu akan mengkonsumsi memori. Disarankan untuk mengubahnya menjadi:
Objek obj = null; for (int i = 0; i <= count; i ++) {obj = objek baru ();}Dengan cara ini, hanya ada satu referensi objek objek dalam memori. Setiap kali objek baru () digunakan, referensi objek objek menunjuk ke objek yang berbeda, tetapi hanya ada satu objek dalam memori, yang sangat menghemat ruang memori.
(13) Berdasarkan pertimbangan efisiensi dan pemeriksaan jenis, array harus digunakan sebanyak mungkin. ArrayList harus digunakan hanya jika ukuran array tidak dapat ditentukan.
(14) Cobalah untuk menggunakan HashMap, ArrayList, dan StringBuilder. Kecuali jika perlu untuk keamanan utas, tidak disarankan untuk menggunakan hashtable, vector, dan stringBuffer. Tiga yang terakhir memiliki overhead kinerja karena penggunaan mekanisme sinkronisasi.
(15) Jangan menyatakan array sebagai final statis publik
Karena ini tidak ada artinya, ini hanya mendefinisikan referensi sebagai final statis, dan konten array masih dapat diubah sesuka hati. Mendeklarasikan array sebagai publik adalah kerentanan keamanan, yang berarti bahwa array dapat diubah oleh kelas eksternal
(16) Cobalah menggunakan kasus tunggal dalam kesempatan yang sesuai
Menggunakan singleton dapat mengurangi beban beban, mempersingkat waktu pemuatan, dan meningkatkan efisiensi pemuatan, tetapi tidak semua tempat cocok untuk singleton. Sederhananya, singleton terutama berlaku untuk tiga aspek berikut:
Kontrol Penggunaan Sumber Daya, Kontrol Generasi Instance Kontrol Akses Bersamaan Sumber Daya Melalui Sinkronisasi Thread, untuk mencapai tujuan menghemat sumber daya untuk mengontrol berbagi data, dan memungkinkan komunikasi antara beberapa proses atau utas yang tidak terkait tanpa membangun asosiasi langsung.
(17) Cobalah untuk menghindari menggunakan variabel statis sesuka hati
Anda harus tahu bahwa ketika suatu objek dirujuk oleh variabel yang didefinisikan sebagai statis, GC biasanya tidak mendaur ulang memori tumpukan yang ditempati oleh objek, seperti:
kelas publik A {private static b b = new b (); }Pada saat ini, siklus hidup variabel statis B sama dengan kelas A. Jika Kelas A tidak dihapus, objek B yang ditunjuk oleh Referensi B akan berada dalam memori sampai program berakhir
(18) Bersihkan sesi waktu yang tidak lagi dibutuhkan dalam waktu
Untuk menghapus sesi yang tidak lagi aktif, banyak server aplikasi memiliki batas waktu sesi default, biasanya 30 menit. Ketika server aplikasi perlu menyimpan lebih banyak sesi, jika ada memori yang tidak mencukupi, sistem operasi akan mentransfer sebagian data ke disk. Server aplikasi juga dapat membuang beberapa sesi yang tidak aktif ke disk sesuai dengan algoritma MRU (paling sering digunakan baru -baru ini), dan bahkan dapat melemparkan pengecualian memori yang tidak memadai. Jika sesi ini akan dibuang ke disk, itu harus diserialisasi terlebih dahulu. Dalam kelompok berskala besar, objek serial itu mahal. Oleh karena itu, ketika sesi tidak lagi diperlukan, metode httpsession yang tidak valid () harus dipanggil tepat waktu untuk menghapus sesi.
(19) Koleksi yang mengimplementasikan antarmuka acak, seperti arraylist, harus menggunakan loop yang paling umum daripada loop foreach untuk dilintasi
Ini direkomendasikan oleh JDK kepada pengguna. Penjelasan JDK API tentang antarmuka acak ACCACCESS adalah: mengimplementasikan antarmuka acak ACCEACCESS digunakan untuk menunjukkan bahwa itu mendukung akses acak cepat. Tujuan utama antarmuka ini adalah untuk memungkinkan algoritma umum mengubah perilaku mereka, sehingga dapat memberikan kinerja yang baik ketika diterapkan pada daftar akses acak atau berkelanjutan. Pengalaman praktis menunjukkan bahwa jika contoh kelas yang mengimplementasikan antarmuka acak ACCHACKESS diakses secara acak, efisiensi menggunakan loop biasa akan lebih tinggi daripada menggunakan loop foreach; Sebaliknya, jika diakses secara berurutan, akan lebih efisien untuk menggunakan iterator. Anda dapat menggunakan kode yang mirip dengan yang berikut untuk membuat penilaian:
if (list instanceof randomAccess) {for (int i = 0; i <list.size (); i ++) {}} else {iterator <?> iterator = list.iterable (); while (iterator.hasnext ()) {iterator.next ()}}Prinsip implementasi yang mendasari loop foreach adalah iterator, lihat Java Sintaks Sugar 1: Parameter panjang variabel dan prinsip loop foreach. Jadi paruh kedua kalimat "Sebaliknya, jika diakses secara berurutan, menggunakan Iterator akan lebih efisien" berarti bahwa instance kelas yang diakses secara berurutan dilintasi menggunakan loop foreach.
(20) Gunakan blok kode sinkron alih -alih metode sinkronisasi
Ini sudah dinyatakan dengan jelas dalam blok Metode Kunci Sinkronisasi Artikel dalam Modul Multi-Threaded. Kecuali dapat ditentukan bahwa seluruh metode perlu disinkronkan, cobalah menggunakan blok kode yang disinkronkan untuk menghindari menyinkronkan kode -kode yang tidak perlu disinkronkan, yang mempengaruhi efisiensi eksekusi kode.
(21) menyatakan konstan sebagai final statis dan menamainya di modal
Dengan cara ini, konten ini dapat dimasukkan ke dalam kumpulan konstan selama kompilasi, menghindari perhitungan nilai konstan yang dihasilkan selama runtime. Selain itu, menyebutkan nama konstanta dalam modal juga dapat memfasilitasi perbedaan antara konstanta dan variabel
(22) Jangan membuat beberapa objek yang tidak digunakan, jangan mengimpor beberapa kelas yang tidak digunakan
Ini tidak masuk akal. Jika "nilai variabel lokal saya tidak digunakan" dan "impor java.util tidak pernah digunakan" muncul dalam kode, maka harap hapus konten yang tidak berguna ini
(23) Hindari penggunaan refleksi selama operasi program
Untuk informasi lebih lanjut, lihat refleksi. Refleksi adalah fungsi yang sangat kuat yang disediakan oleh Java kepada pengguna. Fungsi yang kuat seringkali berarti efisiensi rendah. Tidak disarankan untuk sering menggunakan mekanisme refleksi selama operasi program, terutama metode Invoke metode. Jika memang perlu, pendekatan sugestif adalah untuk membuat objek melalui refleksi dan memasukkannya ke dalam memori ketika proyek dimulai. Pengguna hanya peduli dengan kecepatan respons tercepat saat berinteraksi dengan rekan, dan tidak peduli berapa lama untuk proyek rekan sejawat untuk memulai.
(24) Gunakan kumpulan koneksi database dan kumpulan utas
Kedua kumpulan digunakan untuk menggunakan kembali objek, yang pertama menghindari sering membuka dan penutupan koneksi, dan yang terakhir menghindari penciptaan dan penghancuran benang yang sering
(25) Gunakan aliran input dan output buffered untuk operasi IO
Aliran input dan output buffered, yaitu bufferedreader, bufferedwriter, bufferedInputStream, bufferedoutputStream, yang dapat sangat meningkatkan efisiensi IO
(26) Gunakan ArrayList untuk adegan dengan penyisipan lebih berurutan dan akses acak, dan gunakan LinkedList untuk adegan dengan lebih banyak penghapusan elemen dan penyisipan perantara.
Ini diketahui dengan memahami prinsip -prinsip arraylist dan linkedlist
(27) Jangan biarkan terlalu banyak parameter formal dalam metode publik
Metode publik adalah metode yang disediakan untuk dunia luar. Jika Anda memberikan metode ini terlalu banyak parameter formal, ada dua kelemahan utama:
Melanggar ide pemrograman yang berorientasi objek. Java menekankan bahwa semuanya adalah objek. Terlalu banyak parameter formal dan tidak cocok dengan ide pemrograman yang berorientasi objek. Terlalu banyak parameter yang pasti akan menyebabkan peningkatan probabilitas kesalahan dalam panggilan metode.
Adapun berapa banyak "terlalu banyak" mengacu pada, 3 atau 4. Misalnya, kami menggunakan JDBC untuk menulis metode insertStudentInfo. Ada 10 bidang informasi siswa yang harus dimasukkan ke dalam tabel siswa. 10 parameter ini dapat dienkapsulasi dalam kelas entitas sebagai parameter formal dari metode INSERT.
(28) Ketika variabel string dan konstanta string sama dengan ditulis di depan konstanta string
Ini adalah trik yang relatif umum, jika ada kode berikut:
String str = "123"; if (str.equals ("123")) {...}Disarankan untuk memodifikasinya menjadi:
String str = "123"; if ("123" .Equals (str)) {...}Ini terutama dapat menghindari pengecualian penunjuk nol
(29) Ketahuilah bahwa di Java tidak ada perbedaan antara jika (i == 1) dan if (1 == i), tetapi dari perspektif kebiasaan membaca, disarankan untuk menggunakan yang pertama
Kadang -kadang orang bertanya apakah ada perbedaan antara "if (i == 1)" dan "if (1 == i)"? Ini dimulai dengan C/C ++.
Dalam C/C ++, kondisi penilaian "if (i == 1)" valid, dan didasarkan pada 0 dan non-0. 0 berarti salah, dan non-0 berarti benar. Jika ada kode seperti itu:
int i = 2; if (i == 1) {...} else {...}C/C ++ menilai bahwa "i == 1" tidak valid, sehingga diwakili oleh 0, yaitu salah. Tetapi jika:
int i = 2; if (i = 1) {...} else {...}Jika programmer secara tidak sengaja menulis "if (i == 1)" sebagai "if (i = 1)", maka akan ada masalah. Tetapkan saya ke 1 di dalam IF. Jika Anda menentukan bahwa konten di dalamnya bukan 0, yang dikembalikan benar, tetapi saya jelas 2, dan nilainya dibandingkan adalah 1, false yang harus dikembalikan. Situasi ini sangat mungkin terjadi dalam pengembangan C/C ++ dan akan menyebabkan beberapa kesalahan yang sulit dipahami. Oleh karena itu, untuk menghindari operasi penugasan yang salah pengembang dalam pernyataan IF, disarankan untuk menulis pernyataan IF sebagai:
int i = 2; if (1 == i) {...} else {...}Dengan cara ini, bahkan jika pengembang secara tidak sengaja menulis "1 = i", kompiler C/C ++ dapat memeriksanya sesegera mungkin, karena kami dapat menetapkan nilai variabel I ke 1, tetapi kami tidak dapat menetapkan nilai konstan 1 hingga i.
Namun, di Java, sintaks "if (i = 1)" dari C/C ++ tidak mungkin muncul, karena begitu sintaks ini ditulis, Java akan menyusun dan melaporkan kesalahan "Ketik ketidakcocokan: tidak dapat dikonversi dari int ke boolean". Namun, meskipun tidak ada perbedaan semantik antara "if (i == 1)" dan "if (1 == i)" di Java, akan lebih baik untuk merekomendasikan menggunakan yang pertama dalam hal kebiasaan membaca.
(30) Jangan gunakan metode tostring () pada array
Mari kita lihat apa yang dicetak menggunakan tostring () untuk array:
int i = 2; if (1 == i) {...} else {...}ternyata:
I@18a992f
Niat asli adalah untuk mencetak isi array, tetapi dapat menyebabkan pengecualian pointer nol karena referensi array adalah nol. Namun, meskipun tidak masuk akal untuk array tostring (), konten dalam koleksi dapat dicetak untuk koleksi tostring (), karena kelas induk koleksi, metode objek tostring () ditulis ulang.
(31) Jangan membuat transformasi gaya ke bawah pada tipe data dasar yang berada di luar jangkauan
Ini tidak akan pernah mendapatkan hasil yang diinginkan:
public static void main (string [] args) {long l = 12345678901234l; int i = (int) l; System.out.println (i);}Kami mungkin berharap mendapatkan beberapa dari mereka, tetapi hasilnya adalah:
1942892530
Jelaskan. Long in Java adalah 8 byte dengan 64 bit, sehingga representasi 12345678901234 di komputer harus:
0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010
Data tipe int adalah 4 byte dan 32 bit. 32 bit pertama dari string data biner di atas diambil dari bit rendah:
0111 0011 1100 1110 0010 1111 1111 0010
String biner ini direpresentasikan sebagai desimal 1942892530, jadi ini adalah output konten pada konsol di atas. Dari contoh ini, kita dapat menarik dua kesimpulan:
1. Jenis data default dari tipe integer adalah int, long l = 12345678901234L. Jumlah ini telah melebihi kisaran int, jadi ada L pada akhirnya, menunjukkan bahwa ini adalah nomor tipe yang panjang. Ngomong -ngomong, tipe default jenis floating point adalah ganda, jadi ketika mendefinisikan float, itu harus ditulis sebagai "" float f = 3.5f "
2. Selanjutnya, tulis kalimat lain "int ii = l + i;" dan akan melaporkan kesalahan karena long + int adalah panjang dan tidak dapat ditetapkan untuk int
(32) Data yang tidak digunakan dalam kelas pengumpulan publik harus dihapus tepat waktu
Jika kelas pengumpulan bersifat publik (yaitu, itu bukan properti dalam metode), maka elemen dalam koleksi ini tidak akan secara otomatis dirilis karena selalu ada referensi yang menunjuk ke mereka. Oleh karena itu, jika data tertentu dalam pengumpulan publik tidak digunakan dan tidak dihapus, itu akan menyebabkan pengumpulan publik terus tumbuh, menyebabkan sistem memiliki potensi kebocoran memori.
(33) Konversi tipe data dasar menjadi string. Tipe Data Dasar.
Umumnya ada tiga cara untuk mengonversi tipe data dasar menjadi. Saya memiliki data tipe integer yaitu tostring (), string.valueof (i), dan i+"" Tiga cara. Seberapa efisien tiga cara? Lihat tes:
public static void main (string [] args) {int looptime = 50000; Integer I = 0; Long StartTime = System.CurrentTimeMillis (); untuk (int j = 0; j <looptime; j ++) {string str = string.valueof (i); } System.out.println ("String.ValueOf ():" + (System.CurrentTimeMillis () - StartTime) + "MS"); startTime = system.currentTimeMillis (); untuk (int j = 0; j <looptime; j ++) {string str = i.toString (); } System.out.println ("Integer.ToString ():" + (System.CurrentTimeMillis () - StartTime) + "ms"); startTime = system.currentTimeMillis (); untuk (int j = 0; j <looptime; j ++) {string str = i+""; } System.out.println ("i + /" /":" + (System.currentTimeMillis () - startTime) + "ms");}Hasil berjalan adalah:
String.ValueOf (): 11MSInteger.ToString (): 5ms + "": 25ms
Oleh karena itu, ketika Anda mengonversi tipe data dasar menjadi string di masa depan, Anda harus memberikan prioritas untuk menggunakan metode ToString (). Adapun mengapa, ini sangat sederhana:
Metode String.valueOf() disebut metode Integer.toString() , tetapi akan singkat untuk menilai metode Integer.toString() sebelum menelepon. Saya akan memanggil i + "" Lapisan bawah menggunakan implementasi StringBuilder. Pertama -tama gunakan metode append untuk menyambungkannya, dan kemudian gunakan metode tostring () untuk mendapatkan string.
Dibandingkan dengan ketiganya, ini jelas yang tercepat, tercepat, paling lambat
(34) Gunakan cara paling efisien untuk melintasi peta
Ada banyak cara untuk melintasi peta. Biasanya, apa yang kita butuhkan untuk melintasi kunci dan nilai di peta. Metode yang disarankan dan paling efisien adalah:
public static void main (string [] args) {hashmap <string, string> hm = new HashMap <string, string> (); hm.put ("111", "222"); Atur <map.entry <string, string >> entryset = hm.entryset (); Iterator <map.entry <string, string >> iter = entryset.iterator (); while (iter.hasnext ()) {map.entry <string, string> entri = iter.next (); System.out.println (entry.getKey () + "/t" + entri.getValue ()); }} Jika Anda hanya ingin mengulangi nilai kunci dari peta ini, akan lebih tepat untuk menggunakan " Set<String> keySet = hm.keySet();"
(35) Disarankan untuk beroperasi secara terpisah untuk sumber daya dekat ()
Artinya, misalnya, saya memiliki sepotong kode seperti ini:
coba {xxx.close (); Yyy.close ();} catch (Exception e) {...}Disarankan untuk memodifikasinya menjadi:
coba {xxx.close ();} catch (Exception e) {...} coba {yyy.close ();} catch (Exception e) {...}Meskipun agak merepotkan, ia dapat menghindari kebocoran sumber daya. Kami berpikir bahwa jika tidak ada kode yang dimodifikasi, jika xxx.close () melempar pengecualian, itu akan memasukkan blok tangkapan. Yyy.close () tidak akan dieksekusi, dan sumber daya yyy tidak akan didaur ulang dan akan ditempati sepanjang waktu. Dengan lebih banyak kode seperti ini, ini dapat menyebabkan pegangan sumber daya bocor. Setelah mengubah ke metode penulisan berikut, dijamin bahwa XXX dan YYY akan ditutup apa pun yang terjadi.
(36) Untuk threadlocal, Anda harus menghapus sebelum atau sesudah digunakan
Saat ini, pada dasarnya semua proyek menggunakan teknologi pengumpulan utas, yang sangat bagus. Anda dapat secara dinamis mengonfigurasi jumlah utas dan menggunakan kembali utas.
Namun, jika Anda menggunakan ThreadLocal dalam proyek Anda, ingatlah untuk menghapusnya sebelum atau sesudah digunakan. Ini karena teknologi kumpulan utas yang disebutkan di atas adalah menggunakan kembali utas, yang berarti bahwa selama kode berjalan, utas tidak akan dihancurkan dan akan menunggu penggunaan berikutnya. Mari kita lihat referensi di kelas utas yang memegang threadlocal.threadlocalmap:
/* Nilai utas yang berkaitan dengan utas ini. Peta ini dipertahankan * oleh kelas utas. */Threadlocal.threadlocalmap threadlocals = null;
Utas tidak dihancurkan berarti bahwa data dalam threadlocal.threadlocalmap dari set utas sebelumnya masih ada. Ketika utas berikutnya menggunakan kembali utas ini, kemungkinan yang Anda dapatkan adalah data dari set utas sebelumnya daripada konten yang Anda inginkan.
Masalah ini sangat tidak jelas. Setelah kesalahan yang disebabkan oleh penyebab ini terjadi, sangat sulit untuk menemukan masalah ini tanpa pengalaman yang relevan atau fondasi yang kuat. Karena itu, Anda harus memperhatikan hal ini saat menulis kode, yang akan mengurangi beban kerja Anda berikutnya.
(37) Ingatlah untuk mengganti bilangan iblis dengan definisi konstan. Keberadaan nomor iblis akan sangat mengurangi keterbacaan kode. Apakah konstanta string menggunakan definisi konstan dapat bergantung pada situasi.
(38) Saat penugasan awal panjang atau panjang, gunakan huruf besar L alih -alih huruf kecil L, karena huruf L sangat mudah untuk disamakan dengan nomor 1, poin ini sangat rinci dan patut dicatat
(39) Semua metode penulisan ulang harus mempertahankan anotasi @Override
Ada tiga alasan untuk melakukan ini:
(1) Jelas bahwa metode ini diwarisi dari kelas induk
(2) GetObject () dan get0bject () Metode. Surat keempat yang pertama adalah "O", dan orang tua dan anak keempat yang terakhir adalah "0". Menambahkan anotasi @Override dapat segera menentukan apakah penulisan ulang berhasil.
(3) Ubah tanda tangan metode di kelas abstrak, dan kelas implementasi akan segera melaporkan kesalahan kompilasi.
(40) Disarankan untuk menggunakan kelas alat Objects yang baru diperkenalkan di JDK7 untuk membandingkan objek yang sama, secara langsung A.Equals (b), dan ada risiko pengecualian penunjuk nol.
(41) Jangan gunakan "+" untuk menyambungkan string di badan loop, tetapi gunakan StringBuilder untuk terus menambahkan
Izinkan saya berbicara tentang alasan mengapa saya tidak menggunakan "+" untuk penyambungan string. Jika saya memiliki metode:
Public String appendStr (String oristr, String ... appendStrs) {if (appendStrs == null || appendstrs.length == 0) {return oristr; } untuk (string appendStr: appendStrs) {oristr += appendStr; } return oristr;}Setelah menyusun kode ini, dekompilasi file .class menggunakan javap -c untuk mencegat bagian kunci:
Ini berarti bahwa setiap kali mesin virtual bertemu dengan operator "+" untuk menyambungkan string, itu akan baru A StringBuilder, lalu panggil metode Append, dan akhirnya panggil metode ToString () untuk mengonversi string ke objek ORIST. Artinya, berapa kali loop akan stringbuilder baru (), yang merupakan pemborosan memori.
(42) Jangan menangkap kelas pengecualian runtime yang didefinisikan dalam pustaka kelas java yang diwarisi dari runtimeexception
Efisiensi penanganan pengecualian rendah, sebagian besar kelas runtime runtimeException dapat sepenuhnya dihindari oleh pemrogram, seperti:
(43) Hindari menggunakan instance acak dengan beberapa utas. Meskipun berbagi instance-aman-utas, itu akan menyebabkan degradasi kinerja karena persaingan untuk benih yang sama. Setelah JDK7, Anda dapat menggunakan ThreadLocalrandom untuk mendapatkan nomor acak
Jelaskan alasan mengapa persaingan untuk benih yang sama menyebabkan degradasi kinerja. Misalnya, lihatlah implementasi metode NextInt () dari kelas acak:
publik int nextInt () {return next (32); }Metode berikutnya (int bits) dipanggil, yang merupakan metode yang dilindungi:
intropted int next (int bits) {long oldseed, nextseed; Seed atomiclong = this.seed; do {oldseed = seed.get (); nextseed = (oldseed * Multiplier + addend) & mask; } while (! seed.Comppareandset (oldseed, nextseed)); return (int) (nextseed >>> (48 - bit));}Dan benih di sini adalah variabel global:
/*** Keadaan internal yang terkait dengan generator angka pseudorandom ini. * (Spesifikasi untuk metode dalam kelas ini menggambarkan * komputasi yang sedang berlangsung dari nilai ini.) */ Private Final Atomiclong Seed;
Ketika beberapa utas mendapatkan angka acak pada saat yang sama, mereka akan bersaing untuk benih yang sama, menghasilkan penurunan efisiensi.
(44) Kelas statis, kelas singleton, dan kelas pabrik mengatur konstruktor mereka menjadi pribadi
Ini karena kita tidak perlu baru di luar. Setelah mengatur konstruktor ke pribadi, kami memastikan bahwa kelas -kelas ini tidak akan menghasilkan objek instan.
nota bene
Kode yang sangat baik berasal dari setiap optimasi kecil. Memperhatikan setiap detail tidak hanya dapat meningkatkan efisiensi program, tetapi juga menghindari banyak masalah yang tidak diketahui.
Di atas adalah 44 saran optimasi kode Java yang diperkenalkan oleh editor. Saya harap ini akan membantu Anda. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas Anda tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!