Dengan asumsi saya memiliki ArrayList
ArrayList<MyClass> myList;
Dan saya ingin memanggil toArray, apakah ada alasan kinerja untuk digunakan
MyClass[] arr = myList.toArray(new MyClass[myList.size()]);
lebih
MyClass[] arr = myList.toArray(new MyClass[0]);
?
Saya lebih suka gaya kedua, karena kurang verbose, dan saya berasumsi bahwa kompiler akan memastikan array kosong tidak benar-benar dibuat, tapi saya sudah bertanya-tanya apakah itu benar.
Tentu saja, dalam 99% kasus tidak ada bedanya dengan satu cara atau yang lain, tapi saya ingin menjaga gaya yang konsisten antara kode normal saya dan loop internal yang dioptimalkan ...
java
performance
coding-style
itsadok
sumber
sumber
Jawaban:
Secara berlawanan, versi tercepat, di Hotspot 8, adalah:
Saya telah menjalankan tolok ukur mikro menggunakan jmh hasil dan kode di bawah ini, menunjukkan bahwa versi dengan array kosong secara konsisten mengungguli versi dengan array yang telah ditentukan. Perhatikan bahwa jika Anda dapat menggunakan kembali array yang ada dengan ukuran yang benar, hasilnya mungkin berbeda.
Hasil benchmark (skor dalam mikrodetik, lebih kecil = lebih baik):
Untuk referensi, kodenya:
Anda dapat menemukan hasil yang serupa, analisis lengkap, dan diskusi di posting blog Array of Wisdom of the Ancients . Untuk meringkas: kompiler JVM dan JIT berisi beberapa optimisasi yang memungkinkannya untuk membuat dan menginisialisasi array dengan ukuran baru dengan murah, dan optimisasi tersebut tidak dapat digunakan jika Anda membuat array sendiri.
sumber
MyClass[] arr = myList.stream().toArray(MyClass[]::new);
.. yang saya kira akan lebih lambat. Juga, saya ingin melihat tolok ukur untuk perbedaan dengan deklarasi array. Seperti dalam perbedaan antara:MyClass[] arr = new MyClass[myList.size()]; arr = myList.toArray(arr);
danMyClass[] arr = myList.toArray(new MyClass[myList.size()]);
... atau haruskah tidak ada perbedaan? Saya kira keduanya adalah masalah yang berada di luartoArray
fungsi yang terjadi. Tapi hey! Saya tidak berpikir saya akan belajar tentang perbedaan rumit lainnya.toArray
langsung (semakin kecil ukurannya, semakin besar overhead relatifnya)Pada ArrayList di Java 5 , array akan diisi sudah jika memiliki ukuran yang tepat (atau lebih besar). Karena itu
akan membuat satu objek array, mengisinya dan mengembalikannya ke "arr". Di samping itu
akan membuat dua array. Yang kedua adalah array dari MyClass dengan panjang 0. Jadi ada penciptaan objek untuk objek yang akan dibuang segera. Sejauh kode sumber menunjukkan compiler / JIT tidak dapat mengoptimalkan yang ini sehingga tidak dibuat. Selain itu, dengan menggunakan objek zero-length menghasilkan casting dalam metode toArray () -.
Lihat sumber ArrayList.toArray ():
Gunakan metode pertama sehingga hanya satu objek yang dibuat dan menghindari coran (implisit tapi tetap mahal).
sumber
new Myclass[0]
lebih cepat: shipilev.net/blog/2016/arrays-wisdom-ancientsDari inspeksi JetBrains Intellij Idea:
sumber
JVM modern mengoptimalkan konstruksi array reflektif dalam hal ini, sehingga perbedaan kinerja sangat kecil. Menamai koleksi dua kali dalam kode boilerplate seperti itu bukan ide bagus, jadi saya akan menghindari metode pertama. Keuntungan lain dari yang kedua adalah bahwa ia bekerja dengan koleksi yang disinkronkan dan bersamaan. Jika Anda ingin membuat optimasi, gunakan kembali array kosong (array kosong tidak dapat diubah dan dapat dibagikan), atau gunakan profiler (!).
sumber
private static final MyClass[] EMPTY_MY_CLASS_ARRAY = new MyClass[0]
tidak mencegah array kembali dari sedang dibangun oleh refleksi, tetapi tidak mencegah array tambahan yang dibangun masing-masing setiap kali.MyClass[] arr = myList.stream().toArray(MyClass[]::new);
Apakah akan membantu atau terluka dengan koleksi yang disinkronkan dan bersamaan. Dan mengapa? Silahkan.toArray memeriksa apakah array yang dikirimkan memiliki ukuran yang tepat (yaitu, cukup besar untuk memuat elemen dari daftar Anda) dan jika demikian, gunakan itu. Akibatnya jika ukuran array yang disediakan lebih kecil dari yang dibutuhkan, array baru akan dibuat secara refleksif.
Dalam kasus Anda, array dengan ukuran nol, tidak dapat diubah, sehingga dapat dengan aman dinaikkan ke variabel final statis, yang mungkin membuat kode Anda sedikit lebih bersih, yang menghindari membuat array pada setiap permintaan. Larik baru akan dibuat di dalam metode, jadi itu adalah pembacaan optimalisasi.
Mungkin versi yang lebih cepat adalah untuk melewatkan array dengan ukuran yang benar, tetapi kecuali Anda dapat membuktikan bahwa kode ini adalah hambatan kinerja, lebih suka keterbacaan untuk kinerja runtime sampai terbukti sebaliknya.
sumber
Kasus pertama lebih efisien.
Itu karena dalam kasus kedua:
runtime sebenarnya membuat array kosong (dengan ukuran nol) dan kemudian di dalam metode toArray membuat array lain agar sesuai dengan data aktual. Pembuatan ini dilakukan dengan menggunakan refleksi menggunakan kode berikut (diambil dari jdk1.5.0_10):
Dengan menggunakan formulir pertama, Anda menghindari pembuatan array kedua dan juga menghindari kode refleksi.
sumber
Yang kedua sedikit lebih mudah dibaca, tetapi ada sedikit perbaikan sehingga tidak layak. Metode pertama lebih cepat, tanpa kerugian saat runtime, jadi itulah yang saya gunakan. Tapi saya menulisnya dengan cara kedua, karena lebih cepat untuk mengetik. Kemudian IDE saya menandainya sebagai peringatan dan menawarkan untuk memperbaikinya. Dengan satu penekanan tombol, itu mengubah kode dari tipe kedua ke yang pertama.
sumber
Menggunakan 'toArray' dengan array dengan ukuran yang benar akan berkinerja lebih baik karena alternatif akan membuat pertama array berukuran nol kemudian array dengan ukuran yang benar. Namun, seperti yang Anda katakan, perbedaannya mungkin diabaikan.
Juga, perhatikan bahwa kompiler javac tidak melakukan optimasi apa pun. Hari-hari ini semua optimasi dilakukan oleh kompiler JIT / HotSpot saat runtime. Saya tidak mengetahui adanya optimasi di sekitar 'toArray' di JVM.
Maka, jawaban atas pertanyaan Anda sebagian besar adalah masalah gaya tetapi demi konsistensi harus menjadi bagian dari standar pengkodean apa pun yang Anda patuhi (apakah didokumentasikan atau tidak).
sumber
kode sampel untuk integer:
sumber