Mengapa nama charset bukan konstanta?

211

Masalah charset membingungkan dan rumit dengan sendirinya, tetapi di atas itu Anda harus mengingat nama persis rangkaian karakter Anda. Apakah itu "utf8"? Atau "utf-8"? Atau mungkin "UTF-8"? Saat mencari sampel kode di internet Anda akan melihat semua hal di atas. Mengapa tidak membuat mereka dinamakan konstanta dan digunakan Charset.UTF8?

serg
sumber
19
+1: Ini juga mengganggu saya sepanjang waktu. Kisah yang sama terus berlanjut MessageDigest#getInstance().
BalusC
2
Untuk jawaban yang sebenarnya, Anda harus bertanya kepada seseorang di Sun. Semoga berhasil dengan itu :-)
Stephen C
1
Stephen C: Saya yakin ini sudah dibahas di milis publik. -Seseorang di Sun.
Tom Hawtin - tackline
1
lihat pertanyaan ini
yegor256

Jawaban:

160

Jawaban sederhana untuk pertanyaan yang diajukan adalah bahwa string charset yang tersedia bervariasi dari platform ke platform.

Namun, ada enam yang diperlukan untuk hadir, sehingga konstanta bisa dibuat untuk yang sudah lama. Saya tidak tahu mengapa tidak.

JDK 1.4 melakukan hal yang hebat dengan memperkenalkan tipe Charset. Pada titik ini, mereka tidak akan ingin memberikan konstanta String lagi, karena tujuannya adalah untuk membuat semua orang menggunakan instance Charset. Jadi mengapa tidak memberikan enam konstanta standar Charset? Saya bertanya kepada Martin Buchholz karena dia kebetulan duduk tepat di sebelah saya, dan dia mengatakan tidak ada alasan yang sangat bagus, kecuali bahwa pada saat itu, masih setengah matang - terlalu sedikit API JDK telah dipasang untuk menerima Charset, dan dari yang ada, kelebihan Charset biasanya berkinerja lebih buruk.

Sangat menyedihkan bahwa hanya di JDK 1.6 yang akhirnya mereka selesaikan dengan overload Charset. Dan bahwa situasi kinerja terbelakang ini masih ada (alasan mengapa sangat aneh dan saya tidak dapat menjelaskannya, tetapi terkait dengan keamanan!).

Singkat cerita - tetapkan saja konstanta Anda sendiri, atau gunakan kelas Guava's Charsets yang dihubungkan dengan Tony the Pony (meskipun perpustakaan itu belum benar-benar dirilis).

Memperbarui: a StandardCharsetskelas di JDK 7.

Kevin Bourrillion
sumber
Hanya ingin tahu, tahu kapan akan ada rilis (alpha / beta / apa pun) Guava? Beranda proyek agak sedikit membatasi hal ini.
Jonik
Tidak ada kalkun bagi saya sampai keluar!
Kevin Bourrillion
alasan mengapa ini sangat aneh dan saya tidak dapat menjelaskannya, tetapi terkait dengan keamanan - Anda dapat membuat String yang dapat dimodifikasi melalui charset kustom, namun mereka dapat dibuat bekerja lebih cepat daripada string (yang sebenarnya mencari charset). Ini kelalaian / pengabaian bagaimana String(byte bytes[], int offset, int length, Charset charset)diterapkan. Bahkan, hit kinerja tidak sepele sama sekali ketika membuat string kecil dari byte besar [].
bestsss
7
Tidak adil! Anda memiliki akses ke sumber daya yang luar biasa. = (Saya melihat jawaban lain di mana Anda pernah berkata, "Ya, jadi saya bertanya kepada Josh [Bloch] tentang itu ..."
kevinarpe
PrintStream tidak mendukung Charset
rofrol
102

Dua tahun kemudian, dan Java 7's StandardCharsets sekarang mendefinisikan konstanta untuk 6 charset standar.

Jika Anda terjebak pada Java 5/6, Anda dapat menggunakan konstanta Guava's Charsets , seperti yang disarankan oleh Kevin Bourrillion dan Jon Skeet.

Etienne Neveu
sumber
29

Saya berpendapat bahwa kita dapat melakukan jauh lebih baik dari itu ... mengapa charset yang dijamin tidak dapat diakses secara langsung? Charset.UTF8harus menjadi referensi ke Charset, bukan nama sebagai string. Dengan begitu kita tidak perlu menangani UnsupportedEncodingExceptionsemua tempat.

Pikiran Anda, saya juga berpikir bahwa .NET memilih strategi yang lebih baik dengan default ke UTF-8 di mana-mana. Itu kemudian mengacaukan dengan menamai properti pengkodean "sistem operasi standar" Encoding.Default- yang bukan standar dalam. NET itu sendiri :(

Kembali mengomentari dukungan Java charset - mengapa tidak ada konstruktor untuk FileWriter/ FileReaderyang membutuhkan Charset? Pada dasarnya itu adalah kelas yang hampir tidak berguna karena pembatasan itu - Anda hampir selalu membutuhkan InputStreamReadersekitar FileInputStreamatau yang setara untuk output :(

Perawat, perawat - di mana obat saya?

EDIT: Terpikir oleh saya bahwa ini belum benar-benar menjawab pertanyaan. Jawaban yang sebenarnya mungkin adalah "tidak ada yang terlibat memikirkannya" atau "seseorang yang terlibat berpikir itu adalah ide yang buruk." Saya akan sangat menyarankan bahwa kelas utilitas internal yang menyediakan nama atau rangkaian karakter menghindari duplikasi di sekitar basis kode ... Atau Anda bisa menggunakan yang kami gunakan di Google ketika jawaban ini pertama kali ditulis . (Perhatikan bahwa pada Java 7, Anda hanya akan menggunakannya StandardCharsets.)

Jon Skeet
sumber
2
+1. Tetapi sebagai metode daripada bidang sehingga memungkinkan pemuatan malas (oke, Anda mungkin ingin UTF-8, tetapi ada beberapa charset lain tentang dan Anda mungkin ingin fasilitas serupa untuk mereka). Sayangnya ini sepertinya tidak terlalu populer dengan mereka yang mengambil keputusan.
Tom Hawtin - tackline
Saya cukup senang dengan suatu metode, walaupun saya berharap bahwa dengan bersemangat memuat sangat sedikit charset tidak akan menjadi biaya yang signifikan.
Jon Skeet
1
Kami sedang berjuang untuk menghentikan pemuatan kelas yang bersemangat. / Baru saja melakukan pencarian JDK untuk "UTF-8". Ditemukan 270 kecocokan dalam 165 file. Meskipun banyak yang ada di sampah Apache lama (saya percaya disumbangkan oleh tim saya).
Tom Hawtin - tackline
1
@tackline: Saya kira classloading yang bersemangat adalah salah satu hal yang meningkat dari waktu ke waktu. Beberapa kelas di sini, beberapa kelas di sana - masing-masing secara individual terdengar tidak berbahaya - dapat membuat perbedaan besar.
Jon Skeet
Tautan terakhir, ke Jarsar Charsets, rusak.
LarsH
28

Di Jawa 1.7

import java.nio.charset.StandardCharsets

ex: StandardCharsets.UTF_8 StandardCharsets.US_ASCII

Roger
sumber
5

Keadaan saat ini dari penyandian API meninggalkan sesuatu yang diinginkan. Beberapa bagian dari Java 6 API tidak menerima Charsetdi tempat string (di logging, dom.ls, PrintStream; mungkin ada orang lain). Tidak membantu bahwa penyandian seharusnya memiliki nama kanonik yang berbeda untuk berbagai bagian dari perpustakaan standar.

Saya bisa mengerti bagaimana segala sesuatunya sampai di tempat mereka berada; tidak yakin saya punya ide cemerlang tentang cara memperbaikinya.


Selain itu ...

Anda dapat mencari nama untuk implementasi Java 6 Java di sini .

Untuk UTF-8, nilai kanonik adalah "UTF-8"untuk java.niodan "UTF8"untuk java.langdan java.io. Satu-satunya penyandian yang dibutuhkan JRE untuk didukung adalah: US-ASCII; ISO-8859-1; UTF-8; UTF-16BE; UTF-16LE; UTF-16 .

McDowell
sumber
2
Saya tidak menyesal PrintStream satu, karena kelas dengan jelas mengatakan "Kelas PrintWriter harus digunakan dalam situasi yang memerlukan penulisan karakter daripada byte." (Yang, seperti, semua situasi ...)
Kevin Bourrillion
2

Saya sudah lama mendefinisikan kelas utilitas dengan konstanta UTF_8, ISO_8859_1 dan US_ASCII Charset.

Juga, beberapa waktu yang lalu (2 + tahun) saya melakukan tes kinerja sederhana antara new String( byte[], Charset )dan new String( byte[], String charset_name )dan menemukan bahwa pelaksanaan terakhir adalah jauh lebih cepat. Jika Anda melihat di bawah kap di kode sumber Anda akan melihat bahwa mereka memang mengikuti jalur yang sangat berbeda.

Untuk alasan itu saya memasukkan sebuah utilitas di kelas yang sama

public static String stringFromByteArray (
    final byte[] array,
    final Charset charset
)
{
    try
    {
        return new String( array, charset.name( ) )
    }
    catch ( UnsupportedEncodingException ex )
    {
        // cannot happen
    }
}

Mengapa konstruktor String (byte [], Charset) tidak melakukan hal yang sama, mengalahkan saya.

Alexander Pogrebnyak
sumber
1
Tidak Charsetperlu didaftarkan, sehingga pengecualian bisa terjadi. IIRC, ada beberapa perubahan di JDK7 untuk membuatnya lebih cepat untuk Charsetimplementasi yang dikenal baik (menghilangkan salinan tambahan).
Tom Hawtin - tackline