Apakah fungsi ini akan dimasukkan ke dalam versi Java yang lebih baru?
Adakah yang bisa menjelaskan mengapa saya tidak bisa melakukan ini, seperti cara teknis switch
pernyataan Java ?
java
string
switch-statement
Alex Beardsley
sumber
sumber
"Don't hold your breath."
lol, bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179Jawaban:
Pergantian pernyataan dengan
String
kasus telah diimplementasikan di Java SE 7 , setidaknya 16 tahun setelah mereka pertama kali diminta. Alasan yang jelas untuk keterlambatan itu tidak disediakan, tetapi kemungkinan itu ada hubungannya dengan kinerja.Implementasi di JDK 7
Fitur ini sekarang telah diimplementasikan
javac
dengan proses "de-sugaring"; sintaks tingkat tinggi yang bersih menggunakanString
konstanta dalamcase
deklarasi diperluas pada waktu kompilasi menjadi kode yang lebih kompleks mengikuti suatu pola. Kode yang dihasilkan menggunakan instruksi JVM yang selalu ada.A
switch
denganString
kasing diterjemahkan ke dalam dua sakelar selama kompilasi. Yang pertama memetakan setiap string ke integer unik — posisinya dalam sakelar asli. Ini dilakukan dengan terlebih dahulu menyalakan kode hash label. Kasing yang sesuai adalahif
pernyataan yang menguji kesetaraan string; jika ada tabrakan pada hash, tes ini adalah cascadingif-else-if
. Saklar kedua mencerminkan bahwa dalam kode sumber asli, tetapi mengganti label case dengan posisi yang sesuai. Proses dua langkah ini membuatnya mudah untuk mempertahankan kontrol aliran sakelar asli.Beralih di JVM
Untuk kedalaman teknis lebih lanjut
switch
, Anda dapat merujuk ke Spesifikasi JVM, di mana kompilasi pernyataan switch dijelaskan. Singkatnya, ada dua instruksi JVM yang berbeda yang dapat digunakan untuk sakelar, tergantung pada tingkat konstanta yang digunakan oleh kasing. Keduanya bergantung pada penggunaan konstanta integer untuk setiap kasus untuk dieksekusi secara efisien.Jika konstanta padat, mereka digunakan sebagai indeks (setelah mengurangi nilai terendah) ke dalam tabel petunjuk instruksi —
tableswitch
instruksi.Jika konstanta jarang, pencarian biner untuk kasus yang benar dilakukan —
lookupswitch
instruksi.Dalam de-sugaring sebuah
switch
padaString
benda-benda, baik instruksi yang mungkin untuk digunakan. Thelookupswitch
cocok untuk switch pertama pada kode hash untuk menemukan posisi asli dari kasus ini. Ordinal yang dihasilkan adalah cocok alami untuk atableswitch
.Kedua instruksi membutuhkan konstanta integer yang ditugaskan untuk setiap kasus untuk diurutkan pada waktu kompilasi. Saat runtime, sementara
O(1)
kinerjatableswitch
umumnya tampak lebih baik daripadaO(log(n))
kinerjalookupswitch
, itu memerlukan beberapa analisis untuk menentukan apakah tabel cukup padat untuk membenarkan tradeoff ruang-waktu. Bill Venners menulis sebuah artikel hebat yang membahas hal ini secara lebih rinci, bersama dengan pandangan di bawah kap pada instruksi kontrol aliran Java lainnya.Sebelum JDK 7
Sebelum ke JDK 7,
enum
bisa mendekatiString
switch berbasis. Ini menggunakan metode statisvalueOf
yang dihasilkan oleh kompiler pada setiapenum
jenis. Sebagai contoh:sumber
Pill
untuk mengambil beberapa tindakan berdasarkan padastr
saya berpendapat jika-lain lebih disukai karena memungkinkan Anda untuk menanganistr
nilai-nilai di luar kisaran MERAH, BIRU tanpa perlu menangkap pengecualian darivalueOf
atau secara manual memeriksa kecocokan dengan nama setiap jenis enumerasi yang hanya menambahkan overhead yang tidak perlu. Dalam pengalaman saya itu hanya masuk akal untuk digunakanvalueOf
untuk mengubah menjadi enumerasi jika representasi typesafe dari nilai String diperlukan nanti.(hash >> x) & ((1<<y)-1)
akan menghasilkan nilai yang berbeda untuk setiap string yanghashCode
berbeda, dan(1<<y)
kurang dari dua kali jumlah string (atau pada Setidaknya tidak lebih besar dari itu).Jika Anda memiliki tempat di kode Anda di mana Anda dapat mengaktifkan String, maka mungkin lebih baik untuk refactor String menjadi enumerasi dari nilai yang mungkin, yang dapat Anda aktifkan. Tentu saja, Anda membatasi nilai potensial dari Strings yang dapat Anda miliki dengan yang ada dalam penghitungan, yang mungkin atau mungkin tidak diinginkan.
Tentu saja enumerasi Anda dapat memiliki entri untuk 'lain', dan metode fromString (String), maka Anda bisa memiliki
sumber
Berikut ini adalah contoh lengkap berdasarkan posting JeeBee, menggunakan java enum alih-alih menggunakan metode kustom.
Perhatikan bahwa di Java SE 7 dan yang lebih baru, Anda bisa menggunakan objek String dalam ekspresi statement switch.
sumber
Switch berdasarkan bilangan bulat dapat dioptimalkan menjadi kode yang sangat efisien. Switch berdasarkan tipe data lain hanya dapat dikompilasi ke serangkaian pernyataan if ().
Untuk alasan itu, C&C ++ hanya mengizinkan sakelar pada tipe integer, karena tidak ada gunanya dengan tipe lain.
Para desainer C # memutuskan bahwa gaya itu penting, bahkan jika tidak ada keuntungan.
Para perancang Jawa rupanya berpikir seperti perancang C.
sumber
Contoh
String
penggunaan langsung sejak 1.7 juga dapat ditampilkan:sumber
James Curran dengan singkat mengatakan: "Switch berbasis integer dapat dioptimalkan menjadi kode yang sangat efisien. Switch berdasarkan tipe data lain hanya dapat dikompilasi ke serangkaian pernyataan if (). Untuk alasan itu, C&C ++ hanya mengizinkan switch pada tipe integer, karena tidak ada gunanya dengan tipe lain. "
Pendapat saya, dan hanya itu, adalah bahwa begitu Anda mulai beralih pada non-primitif Anda harus mulai berpikir tentang "sama dengan" versus "==". Pertama membandingkan dua string bisa menjadi prosedur yang cukup panjang, menambah masalah kinerja yang disebutkan di atas. Kedua jika ada mengaktifkan string akan ada permintaan untuk beralih pada kasus mengabaikan string, beralih pada string mempertimbangkan / mengabaikan lokal, beralih pada string berdasarkan regex .... Saya akan menyetujui keputusan yang menghemat banyak waktu untuk pengembang bahasa dengan biaya sejumlah kecil waktu untuk programmer.
sumber
matched
dannot matched
. (Meskipun tidak memperhitungkan hal-hal seperti kelompok [yang dinamai] / etc.)Selain argumen yang baik di atas, saya akan menambahkan bahwa banyak orang hari ini melihat
switch
sebagai sisa masa lalu prosedural Jawa (kembali ke C kali).Saya tidak sepenuhnya berbagi pendapat ini, saya pikir
switch
dapat memiliki kegunaannya dalam beberapa kasus, setidaknya karena kecepatannya, dan lagi pula itu lebih baik daripada beberapa seri cascading numerik yangelse if
saya lihat dalam beberapa kode ...Tetapi memang, ada baiknya melihat kasus di mana Anda perlu beralih, dan melihat apakah itu tidak dapat diganti oleh sesuatu yang lebih OO. Misalnya enum di Java 1.5+, mungkin HashTable atau koleksi lain (kadang saya menyesal kami tidak memiliki fungsi (anonim) sebagai warga negara kelas satu, seperti di Lua - yang tidak memiliki saklar - atau JavaScript) atau bahkan polimorfisme.
sumber
Jika Anda tidak menggunakan JDK7 atau lebih tinggi, Anda bisa menggunakannya
hashCode()
untuk mensimulasikannya. KarenaString.hashCode()
biasanya mengembalikan nilai yang berbeda untuk string yang berbeda dan selalu mengembalikan nilai yang sama untuk string yang sama, itu cukup dapat diandalkan (String yang berbeda dapat menghasilkan kode hash yang sama seperti @Lii yang disebutkan dalam komentar, seperti"FB"
dan"Ea"
) Lihat dokumentasi .Jadi, kodenya akan terlihat seperti ini:
Dengan begitu, Anda secara teknis mengaktifkan
int
.Atau, Anda dapat menggunakan kode berikut:
sumber
case
pernyataan harus, saya pikir, selalu nilai konstan, danString.hashCode()
tidak seperti itu (bahkan jika dalam praktiknya perhitungan tidak pernah berubah antara JVM).case
nilai-nilai pernyataan tidak harus ditentukan pada saat kompilasi jadi itu berfungsi dengan baik.Selama bertahun-tahun kami telah menggunakan preprosesor (n open source) untuk ini.
File yang telah diproses diberi nama Foo.jpp dan diproses menjadi Foo.java dengan skrip semut.
Keuntungannya adalah ia diproses menjadi Java yang berjalan pada 1.0 (walaupun biasanya kami hanya mendukung kembali ke 1.4). Juga jauh lebih mudah untuk melakukan ini (banyak switch string) dibandingkan dengan fudging dengan enum atau solusi lain - kode jauh lebih mudah untuk dibaca, dipelihara, dan dipahami. IIRC (tidak dapat memberikan statistik atau alasan teknis pada saat ini) juga lebih cepat dari padanan Java alami.
Kerugiannya adalah Anda tidak mengedit Java sehingga alur kerjanya sedikit lebih (edit, proses, kompilasi / tes) ditambah IDE akan menghubungkan kembali ke Java yang sedikit berbelit-belit (sakelar menjadi serangkaian langkah logika if / else) dan urutan sakelar tidak dipertahankan.
Saya tidak akan merekomendasikan ini untuk 1.7+ tetapi ini berguna jika Anda ingin memprogram Java yang menargetkan JVM sebelumnya (karena Joe public jarang memiliki yang terbaru diinstal).
Anda bisa mendapatkannya dari SVN atau menelusuri kode secara online . Anda akan membutuhkan EBuild untuk membangunnya apa adanya.
sumber
Jawaban lain mengatakan ini ditambahkan di Java 7 dan diberikan solusi untuk versi sebelumnya. Jawaban ini mencoba menjawab "mengapa"
Java adalah reaksi terhadap kompleksitas C ++ yang berlebihan. Itu dirancang untuk menjadi bahasa bersih yang sederhana.
String mendapat sedikit penanganan kasus khusus dalam bahasa ini, tetapi tampaknya jelas bagi saya bahwa perancang berusaha untuk menjaga jumlah casing khusus dan gula sintaksis seminimal mungkin.
menyalakan string cukup rumit di bawah kap karena string bukan tipe primitif sederhana. Itu bukan fitur umum pada saat Java dirancang dan tidak benar-benar cocok dengan desain minimalis. Terutama karena mereka telah memutuskan untuk tidak memberikan case khusus == untuk string, itu akan (dan) agak aneh untuk case untuk bekerja di mana == tidak.
Antara 1,0 dan 1,4 bahasa itu sendiri tetap hampir sama. Sebagian besar perangkat tambahan ke Jawa berada di sisi perpustakaan.
Itu semua berubah dengan Java 5, bahasanya diperluas secara substansial. Perpanjangan lebih lanjut diikuti dalam versi 7 dan 8. Saya berharap bahwa perubahan sikap ini didorong oleh munculnya C #
sumber
JEP 354: Alihkan Ekspresi (Pratinjau) di JDK-13 dan JEP 361: Alihkan Ekspresi (Standar) di JDK-14 akan memperluas pernyataan sakelar sehingga dapat digunakan sebagai ekspresi .
Sekarang kamu bisa:
case L ->
):Jadi demo dari jawaban ( 1 , 2 ) mungkin terlihat seperti ini:
sumber
Tidak terlalu cantik, tapi di sini ada cara lain untuk Java 6 dan di bawah:
sumber
Sangat mudah di Groovy; Saya menanamkan toples asyik dan membuat
groovy
kelas utilitas untuk melakukan semua hal ini dan banyak lagi yang menurut saya menjengkelkan untuk dilakukan di Jawa (karena saya terjebak menggunakan Java 6 di perusahaan.)sumber
Saat Anda menggunakan intellij, lihat juga:
File -> Struktur Proyek -> Proyek
File -> Struktur Proyek -> Modul
Ketika Anda memiliki banyak modul, pastikan Anda mengatur level bahasa yang benar di tab modul.
sumber
sumber