Pandangan mendalam tentang tipe karakter Java

Versi 1.1 Java memperkenalkan sejumlah kelas untuk menangani karakter. Kelas-kelas baru ini membuat abstraksi untuk mengubah gagasan khusus platform tentang nilai karakter menjadi nilai Unicode . Kolom ini membahas apa yang telah ditambahkan, dan motivasi untuk menambahkan kelas karakter ini.

Ketik char

Mungkin tipe dasar yang paling sering disalahgunakan dalam bahasa C adalah tipe char . The Char jenis disalahgunakan sebagian karena ditetapkan menjadi 8 bit, dan selama 25 tahun terakhir, 8 bit juga telah mendefinisikan potongan terpisahkan terkecil dari memori pada komputer. Ketika Anda menggabungkan fakta terakhir dengan fakta bahwa himpunan karakter ASCII telah didefinisikan agar sesuai dalam 7 bit, tipe karakter membuat tipe "universal" yang sangat nyaman. Selanjutnya, di C, pointer ke variabel tipe char menjadi tipe pointer universal karena apa pun yang bisa direferensikan sebagai char juga bisa direferensikan sebagai tipe lain melalui penggunaan casting.

Penggunaan dan penyalahgunaan tipe karakter dalam bahasa C menyebabkan banyak ketidaksesuaian antara implementasi kompilator, jadi dalam standar ANSI untuk C, dua perubahan spesifik dibuat: Pointer universal didefinisikan ulang untuk memiliki tipe kekosongan, sehingga membutuhkan deklarasi oleh programmer; dan nilai numerik dari karakter dianggap bertanda tangan, sehingga menentukan bagaimana mereka akan diperlakukan ketika digunakan dalam perhitungan numerik. Kemudian, pada pertengahan 1980-an, para insinyur dan pengguna menemukan bahwa 8 bit tidak cukup untuk mewakili semua karakter di dunia. Sayangnya, pada saat itu, C sudah begitu mengakar sehingga orang tidak mau, bahkan mungkin tidak mampu, mengubah definisi karakter.Tipe. Sekarang kilas balik ke tahun 90-an, ke awal mula Java. Salah satu dari banyak prinsip yang ditetapkan dalam desain bahasa Java adalah bahwa karakter berukuran 16 bit. Pilihan ini mendukung penggunaan Unicode , cara standar untuk merepresentasikan berbagai jenis karakter dalam berbagai bahasa. Sayangnya, hal itu juga mengatur panggung untuk berbagai masalah yang baru sekarang sedang diperbaiki.

Apa sih karakter itu?

Aku tahu aku dalam kesulitan ketika saya menemukan diri saya mengajukan pertanyaan, "Jadi apa yang karakter?" Nah, karakter adalah surat, bukan? Sekumpulan huruf membentuk sebuah kata, kata membentuk kalimat, dan sebagainya. Kenyataannya, bagaimanapun, adalah bahwa hubungan antara representasi karakter di layar komputer, yang disebut mesin terbangnya , dengan nilai numerik yang menentukan mesin terbang itu, yang disebut a code point, sama sekali tidak langsung.

Saya menganggap diri saya beruntung menjadi penutur asli bahasa Inggris. Pertama, karena itu adalah bahasa umum dari sejumlah besar orang yang berkontribusi pada desain dan pengembangan komputer digital modern; kedua, karena memiliki jumlah mesin terbang yang relatif kecil. Ada 96 karakter yang dapat dicetak dalam definisi ASCII yang dapat digunakan untuk menulis bahasa Inggris. Bandingkan ini dengan bahasa Cina, di mana ada lebih dari 20.000 mesin terbang yang ditentukan dan definisi itu tidak lengkap. Dari permulaan awal dalam kode Morse dan Baudot, kesederhanaan keseluruhan (beberapa mesin terbang, frekuensi kemunculan statistik) dari bahasa Inggris telah menjadikannya lingua-franca di era digital. Namun seiring dengan meningkatnya jumlah orang yang memasuki era digital, jumlah penutur bahasa Inggris non-native juga meningkat. Saat jumlahnya bertambah,semakin banyak orang semakin enggan menerima bahwa komputer menggunakan ASCII dan hanya berbicara bahasa Inggris. Ini sangat meningkatkan jumlah "karakter" yang dibutuhkan komputer untuk memahami. Akibatnya, jumlah mesin terbang yang dikodekan oleh komputer harus berlipat ganda.

Jumlah karakter yang tersedia berlipat ganda ketika kode ASCII 7-bit yang terhormat dimasukkan ke dalam pengkodean karakter 8-bit yang disebut ISO Latin-1 (atau ISO 8859_1, "ISO" menjadi Organisasi Standar Internasional). Seperti yang mungkin telah Anda kumpulkan dari nama pengkodean, standar ini memungkinkan representasi dari banyak bahasa turunan latin yang digunakan di benua Eropa. Namun, hanya karena standar dibuat, bukan berarti itu dapat digunakan. Pada saat itu, banyak komputer sudah mulai menggunakan 128 "karakter" lain yang mungkin diwakili oleh karakter 8-bit untuk beberapa keuntungan. Dua contoh yang masih ada dari penggunaan karakter tambahan ini adalah IBM Personal Computer (PC), dan terminal komputer paling populer yang pernah ada, Digital Equipment Corporation VT-100.Yang terakhir hidup dalam bentuk perangkat lunak emulator terminal.

Waktu kematian sebenarnya untuk karakter 8-bit tidak diragukan lagi akan diperdebatkan selama beberapa dekade, tetapi saya mematoknya pada pengenalan komputer Macintosh pada tahun 1984. Macintosh membawa dua konsep yang sangat revolusioner ke dalam komputasi arus utama: font karakter yang disimpan di RAM; dan WorldScript, yang dapat digunakan untuk mewakili karakter dalam bahasa apa pun. Tentu saja, ini hanyalah salinan dari apa yang telah dikirimkan Xerox pada mesin kelas Dandelion dalam bentuk sistem pengolah kata Star, tetapi Macintosh membawa set karakter dan font baru ini ke audiens yang masih menggunakan terminal "bodoh". . Begitu dimulai, penggunaan font yang berbeda tidak dapat dihentikan - terlalu menarik bagi banyak orang. Di akhir tahun 80-an,tekanan untuk membakukan penggunaan semua karakter ini memuncak dengan pembentukan Unicode Consortium, yang menerbitkan spesifikasi pertamanya pada tahun 1990. Sayangnya, selama tahun 80-an dan bahkan hingga 90-an, jumlah set karakter berlipat ganda. Sangat sedikit insinyur yang membuat kode karakter baru pada saat itu menganggap standar Unicode yang baru lahir layak, sehingga mereka membuat pemetaan kode mereka sendiri untuk mesin terbang. Jadi sementara Unicode tidak diterima dengan baik, gagasan bahwa hanya ada 128 atau paling banyak 256 karakter yang tersedia sudah pasti hilang. Setelah Macintosh, dukungan untuk font yang berbeda menjadi fitur yang harus dimiliki untuk pengolah kata. Delapan karakter bit memudar menuju kepunahan.80-an dan bahkan ke tahun 90-an, jumlah himpunan karakter dikalikan. Sangat sedikit insinyur yang membuat kode karakter baru pada saat itu menganggap standar Unicode yang baru lahir layak, sehingga mereka membuat pemetaan kode mereka sendiri untuk mesin terbang. Jadi sementara Unicode tidak diterima dengan baik, gagasan bahwa hanya ada 128 atau paling banyak 256 karakter yang tersedia sudah pasti hilang. Setelah Macintosh, dukungan untuk font yang berbeda menjadi fitur yang harus dimiliki untuk pengolah kata. Delapan karakter bit memudar menuju kepunahan.80-an dan bahkan ke tahun 90-an, jumlah himpunan karakter dikalikan. Sangat sedikit insinyur yang membuat kode karakter baru pada saat itu menganggap standar Unicode yang baru lahir layak, dan karena itu mereka membuat pemetaan kode mereka sendiri ke mesin terbang. Jadi sementara Unicode tidak diterima dengan baik, gagasan bahwa hanya ada 128 atau paling banyak 256 karakter yang tersedia sudah pasti hilang. Setelah Macintosh, dukungan untuk font yang berbeda menjadi fitur yang harus dimiliki untuk pengolah kata. Delapan karakter bit memudar menuju kepunahan.Gagasan bahwa hanya ada 128 atau paling banyak 256 karakter yang tersedia sudah pasti hilang. Setelah Macintosh, dukungan untuk font yang berbeda menjadi fitur yang harus dimiliki untuk pengolah kata. Delapan karakter bit memudar menuju kepunahan.Gagasan bahwa hanya ada 128 atau paling banyak 256 karakter yang tersedia sudah pasti hilang. Setelah Macintosh, dukungan untuk font yang berbeda menjadi fitur yang harus dimiliki untuk pengolah kata. Delapan karakter bit memudar menuju kepunahan.

Java dan Unicode

Saya memasuki cerita pada tahun 1992 ketika saya bergabung dengan kelompok Oak (Bahasa Jawa disebut Oak ketika pertama kali dikembangkan) di Sun. Tipe dasar chardidefinisikan sebagai 16 bit unsigned, satu-satunya tipe unsigned di Java. Alasan untuk karakter 16-bit adalah bahwa ia akan mendukung representasi karakter Unicode apa pun, sehingga membuat Java cocok untuk mewakili string dalam bahasa apa pun yang didukung oleh Unicode. Tapi bisa mewakili string dan bisa mencetaknya selalu menjadi masalah tersendiri. Mengingat bahwa sebagian besar pengalaman dalam grup Oak berasal dari sistem Unix dan sistem turunan Unix, rangkaian karakter yang paling nyaman adalah, sekali lagi, ISO Latin-1. Selain itu, dengan warisan Unix dari grup, sistem Java I / O dimodelkan sebagian besar pada abstraksi aliran Unix di mana setiap perangkat I / O dapat diwakili oleh aliran byte 8-bit. Kombinasi ini meninggalkan sesuatu yang salah dalam bahasa antara perangkat input 8-bit dan karakter Java 16-bit. Jadi,di mana pun string Java harus dibaca atau ditulis ke aliran 8-bit, ada sedikit kode, peretasan, untuk secara ajaib memetakan karakter 8 bit menjadi unicode 16 bit.

Pada Java Developer Kit (JDK) versi 1.0, peretasan masukan ada di dalam DataInputStreamkelas, dan peretasan keluaran adalah seluruh PrintStreamkelas. (Sebenarnya ada kelas input bernama TextInputStreamdalam rilis alfa 2 Java, tetapi digantikan oleh DataInputStreamperetasan dalam rilis sebenarnya.) Hal ini terus menyebabkan masalah bagi pemrogram Java pemula, karena mereka mati-matian mencari Java yang setara dengan C fungsi getc(). Pertimbangkan program Java 1.0 berikut:

impor java.io. *; kelas publik palsu {public static void main (String args []) {FileInputStream fis; DataInputStream dis; char c; coba {fis = new FileInputStream ("data.txt"); dis = new DataInputStream (fis); sementara (benar) {c = dis.readChar (); System.out.print (c); System.out.flush (); jika (c == '\ n') putus; } fis.close (); } menangkap (Pengecualian e) {} System.exit (0); }}

Sekilas, program ini akan muncul untuk membuka file, membacanya satu karakter pada satu waktu, dan keluar saat baris baru pertama dibaca. Namun, dalam praktiknya, yang Anda dapatkan adalah keluaran sampah. Dan alasan Anda mendapatkan sampah adalah readChar membaca karakter Unicode 16-bit dan System.out.printmencetak apa yang diasumsikan sebagai karakter ISO Latin-1 8-bit. Namun, jika Anda mengubah program di atas untuk menggunakan fungsi readLineDataInputStream , itu akan tampak berfungsi karena kode di readLinemembaca format yang didefinisikan dengan memberikan anggukan ke spesifikasi Unicode sebagai "UTF-8 yang dimodifikasi." (UTF-8 adalah format yang ditentukan Unicode untuk mewakili karakter Unicode dalam aliran input 8-bit.) Jadi situasi di Java 1.0 adalah bahwa string Java terdiri dari karakter Unicode 16-bit, tetapi hanya ada satu pemetaan yang memetakan Karakter ISO Latin-1 ke dalam Unicode. Untungnya, Unicode mendefinisikan halaman kode "0" - yaitu, 256 karakter yang 8 bit teratasnya semuanya nol - agar sesuai dengan set ISO Latin-1. Dengan demikian, pemetaannya cukup sepele, dan selama Anda hanya menggunakan file karakter ISO Latin-1, Anda tidak akan mengalami masalah saat data meninggalkan file, dimanipulasi oleh kelas Java, dan kemudian ditulis ulang ke file. .

Ada dua masalah dengan mengubur kode konversi input ke dalam kelas-kelas ini: Tidak semua platform menyimpan file multibahasa mereka dalam format UTF-8 yang dimodifikasi; dan tentunya, aplikasi pada platform ini tidak selalu mengharapkan karakter non-Latin dalam formulir ini. Oleh karena itu, dukungan implementasi tidak lengkap, dan tidak ada cara mudah untuk menambahkan dukungan yang dibutuhkan di rilis selanjutnya.

Java 1.1 dan Unicode

The Java 1.1 release introduced an entirely new set of interfaces for handling characters, called Readers and Writers. I modified the class named bogus from above into a class named cool. The cool class uses an InputStreamReader class to process the file rather than the DataInputStream class. Note that InputStreamReader is a subclass of the new Reader class and the System.out is now a PrintWriter object, which is a subclass of the Writer class. The code for this example is shown below:

import java.io.*; public class cool { public static void main(String args[]) { FileInputStream fis; InputStreamReader irs; char c; try { fis = new FileInputStream("data.txt"); irs = new InputStreamReader(fis); System.out.println("Using encoding : "+irs.getEncoding()); while (true) { c = (char) irs.read(); System.out.print(c); System.out.flush(); if (c == '\n') break; } fis.close(); } catch (Exception e) { } System.exit(0); } } 

The primary difference between this example and the previous code listing is the use of the InputStreamReader class rather than the DataInputStream class. Another way in which this example is different from the previous one is that there is an additional line that prints out the encoding used by the InputStreamReader class.

The important point is that the existing code, once undocumented (and ostensibly unknowable) and embedded inside the implementation of the getChar method of the DataInputStream class, has been removed (actually its use is deprecated; it will be removed in a future release). In the 1.1 version of Java, the mechanism that performs the conversion is now encapsulated in the Reader class. This encapsulation provides a way for the Java class libraries to support many different external representations of non-Latin characters while always using Unicode internally.

Of course, like the original I/O subsystem design, there are symmetric counterparts to the reading classes that perform writing. The class OutputStreamWriter can be used to write strings to an output stream, the class BufferedWriter adds a layer of buffering, and so on.

Trading warts or real progress?

The somewhat lofty goal of the design of the Reader and Writerclasses was to tame what is currently a hodge-podge of representation standards for the same information by providing a standard way of converting back and forth between the legacy representation -- be it Macintosh Greek or Windows Cyrillic -- and Unicode. So, a Java class that deals with strings need not change when it moves from platform to platform. This might be the end of the story, except that now that the conversion code is encapsulated, the question arises as to what that code assumes.

Saat meneliti kolom ini, saya teringat kutipan terkenal dari seorang eksekutif Xerox (sebelum itu adalah Xerox, ketika itu adalah Perusahaan Haloid) tentang mesin fotokopi yang berlebihan karena cukup mudah bagi seorang sekretaris untuk memasukkan selembar kertas karbon ke dalamnya. mesin tiknya dan membuat salinan dokumen saat dia membuat aslinya. Tentu saja, yang jelas di belakang adalah bahwa mesin fotokopi lebih bermanfaat bagi orang yang menerima dokumen daripada orang yang menghasilkan dokumen. JavaSoft telah menunjukkan kurangnya pemahaman yang sama tentang penggunaan kelas encoding dan decoding karakter dalam desain mereka pada bagian sistem ini.