Saya sedang membaca Java ArrayList
kode sumber dan melihat beberapa perbandingan dalam pernyataan if.
Di Java 7, metode ini grow(int)
menggunakan
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
Di Java 6, grow
tidak ada. ensureCapacity(int)
Namun metode ini menggunakan
if (newCapacity < minCapacity)
newCapacity = minCapacity;
Apa alasan di balik perubahan itu? Apakah itu masalah kinerja atau hanya gaya?
Saya bisa membayangkan bahwa membandingkan dengan nol lebih cepat, tetapi melakukan pengurangan lengkap hanya untuk memeriksa apakah itu negatif tampaknya sedikit berlebihan bagi saya. Juga dalam hal bytecode, ini akan melibatkan dua instruksi ( ISUB
dan IF_ICMPGE
) bukannya satu ( IFGE
).
java
if-statement
arraylist
dejvuth
sumber
sumber
if (newCapacity - minCapacity < 0)
lebih baik daripadaif (newCapacity < minCapacity)
dalam hal mencegah overflow?Jawaban:
a < b
dana - b < 0
dapat berarti dua hal yang berbeda. Pertimbangkan kode berikut:Saat dijalankan, ini hanya akan dicetak
a - b < 0
. Apa yang terjadi adalah yanga < b
jelas salah, tetapia - b
meluap dan menjadi-1
, yang negatif.Sekarang, setelah mengatakan itu, pertimbangkan bahwa array memiliki panjang yang sangat dekat
Integer.MAX_VALUE
. Kode dalamArrayList
seperti ini:oldCapacity
sangat dekatInteger.MAX_VALUE
sehingganewCapacity
(yangoldCapacity + 0.5 * oldCapacity
) mungkin meluap dan menjadiInteger.MIN_VALUE
(yaitu negatif). Kemudian, kurangiminCapacity
arus balik kembali ke angka positif.Pemeriksaan ini memastikan bahwa
if
tidak dieksekusi. Jika kode ditulis sebagaiif (newCapacity < minCapacity)
, maka akantrue
dalam hal ini (karenanewCapacity
negatif) jadinewCapacity
akan dipaksa untukminCapacity
terlepas darioldCapacity
.Case overflow ini ditangani oleh if berikutnya. Ketika
newCapacity
telah meluap, ini akantrue
:MAX_ARRAY_SIZE
didefinisikan sebagaiInteger.MAX_VALUE - 8
danInteger.MIN_VALUE - (Integer.MAX_VALUE - 8) > 0
adalahtrue
. KarenanewCapacity
itu ditangani dengan benar:hugeCapacity
metode mengembalikanMAX_ARRAY_SIZE
atauInteger.MAX_VALUE
.NB: inilah yang dikatakan oleh
// overflow-conscious code
komentar dalam metode ini.sumber
a - b
dan memeriksa apakah bit atas adalah a1
. Bagaimana mereka menangani overflow?Saya menemukan penjelasan ini :
Di Java 6, jika Anda menggunakan API sebagai:
Dan
newCount
melimpah (ini menjadi negatif),if (minCapacity > oldCapacity)
akan kembali salah dan Anda mungkin salah berasumsi bahwaArrayList
itu meningkatlen
.sumber
ensureCapacity
; jikaminCapacity
negatif, Anda tidak pernah sampai ke titik itu — sama saja diam-diam diabaikan seperti implementasi rumit yang berpura-pura mencegah. Jadi "kita tidak bisa melakukan ini" untuk kompatibilitas API publik adalah argumen yang aneh seperti yang sudah mereka lakukan. Satu-satunya penelepon yang mengandalkan perilaku ini adalah penelepon internal.minCapacity
sangat negatif (yaitu dihasilkan dariint
melimpah ketika menambahkan ukuran ArrayList saat ini ke jumlah elemen yang ingin Anda tambahkan),minCapacity - elementData.length
untuk meluap lagi dan menjadi positif. Begitulah cara saya memahaminya.if (minCapacity > minExpand)
, yang saya tidak mengerti.addAll
metode adalah satu-satunya kasus yang relevan karena jumlah ukuran saat ini dan jumlah elemen baru dapat meluap. Namun demikian, ini adalah panggilan internal dan argumen "kami tidak dapat mengubahnya karenaensureCapacity
merupakan API publik" adalah argumen aneh ketika pada kenyataannya,ensureCapacity
memang mengabaikan nilai-nilai negatif. Java 8 API tidak mengubah perilaku itu, yang dilakukannya adalah mengabaikan kapasitas di bawah kapasitas default ketikaArrayList
sedang dalam kondisi awal (yaitu diinisialisasi dengan kapasitas default dan masih kosong).newcount = count + len
itu benar dalam hal penggunaan internal, namun, itu tidak berlaku untukpublic
metode iniensureCapacity()
...Melihat kode:
Jika
oldCapacity
cukup besar, ini akan meluap, dannewCapacity
akan menjadi angka negatif. Perbandingan sepertinewCapacity < oldCapacity
akan salah mengevaluasitrue
danArrayList
akan gagal tumbuh.Sebagai gantinya, kode yang ditulis (
newCapacity - minCapacity < 0
mengembalikan salah) akan memungkinkan nilai negatifnewCapacity
untuk dievaluasi lebih lanjut di baris berikutnya, menghasilkan penghitungan ulangnewCapacity
dengan memanggilhugeCapacity
(newCapacity = hugeCapacity(minCapacity);
) untuk memungkinkan untukArrayList
tumbuh hinggaMAX_ARRAY_SIZE
.Inilah yang
// overflow-conscious code
coba dikomentari oleh komentar itu, meskipun agak tidak jelas.Jadi, intinya, perbandingan baru melindungi terhadap pengalokasian yang
ArrayList
lebih besar dari yang telah ditetapkanMAX_ARRAY_SIZE
sementara memungkinkannya tumbuh hingga batas itu jika diperlukan.sumber
Kedua bentuk berperilaku persis sama kecuali jika ekspresi
a - b
meluap, dalam hal ini mereka bertolak belakang. Jikaa
negatif besar, danb
positif besar, maka(a < b)
jelas benar, tetapia - b
akan meluap menjadi positif, begitu(a - b < 0)
juga salah.Jika Anda terbiasa dengan kode rakitan x86, pertimbangkan yang
(a < b)
diterapkan oleh ajge
, yang bercabang di sekitar badan pernyataan if ketika SF = OF. Di sisi lain,(a - b < 0)
akan bertindak seperti ajns
, yang bercabang ketika SF = 0. Oleh karena itu, ini berperilaku berbeda saat OF = 1.sumber