Panduan Praktikal untuk DecimalFormat

1. Gambaran keseluruhan

Dalam artikel ini, kita akan meneroka kelas DecimalFormat bersama dengan penggunaan praktikalnya.

Ini adalah subkelas NumberFormat , yang memungkinkan memformat representasi String nombor perpuluhan menggunakan corak yang telah ditentukan.

Ia juga dapat digunakan secara terbalik, untuk menguraikan String menjadi angka.

2. Bagaimana Ia Berfungsi?

Untuk memformat nombor, kita harus menentukan pola, yang merupakan urutan watak khas yang berpotensi dicampur dengan teks.

Terdapat 11 Karakter Corak Khas, tetapi yang paling penting adalah:

  • 0 - mencetak digit jika disediakan, 0 sebaliknya
  • # - mencetak digit jika disediakan, tidak lain
  • . - nyatakan di mana meletakkan pemisah perpuluhan
  • , - nyatakan di mana meletakkan pemisah pengelompokan

Apabila corak mendapat digunakan untuk nombor, peraturan pemformatan dilaksanakan, dan hasilnya dicetak mengikut DecimalFormatSymbol daripada JVM yang kami Locale kecuali tentu yang Locale dinyatakan.

Output contoh berikut adalah dari JVM yang berjalan di English Locale .

3. Pemformatan Asas

Sekarang mari kita lihat output mana yang dihasilkan ketika memformat nombor yang sama dengan corak berikut.

3.1. Perpuluhan Sederhana

double d = 1234567.89; assertThat( new DecimalFormat("#.##").format(d)).isEqualTo("1234567.89"); assertThat( new DecimalFormat("0.00").format(d)).isEqualTo("1234567.89"); 

Seperti yang kita lihat, bahagian integer tidak pernah dibuang, tidak kira sama ada coraknya lebih kecil daripada bilangannya.

assertThat(new DecimalFormat("#########.###").format(d)) .isEqualTo("1234567.89"); assertThat(new DecimalFormat("000000000.000").format(d)) .isEqualTo("001234567.890"); 

Sekiranya coraknya lebih besar daripada angka, angka nol ditambahkan, sementara hash jatuh, baik dalam bilangan bulat dan di bahagian perpuluhan.

3.2. Pembundaran

Sekiranya bahagian perpuluhan corak tidak dapat mengandungi ketepatan keseluruhan nombor masukan, ia akan dibulatkan.

Di sini, bahagian .89 telah dibundarkan menjadi 0,90, kemudian 0 telah dijatuhkan:

assertThat(new DecimalFormat("#.#").format(d)) .isEqualTo("1234567.9"); 

Di sini, bahagian .89 telah dibundarkan menjadi 1.00, kemudian .00 telah dijatuhkan dan 1 telah dijumlahkan ke 7:

assertThat(new DecimalFormat("#").format(d)) .isEqualTo("1234568"); 

Mod pembulatan lalai adalah HALF_EVEN, tetapi boleh disesuaikan melalui kaedah setRoundingMode .

3.3. Pengumpulan

Pemisah pengelompokan digunakan untuk menentukan sub-pola yang berulang secara automatik:

assertThat(new DecimalFormat("#,###.#").format(d)) .isEqualTo("1,234,567.9"); assertThat(new DecimalFormat("#,###").format(d)) .isEqualTo("1,234,568"); 

3.4. Corak Pengumpulan Berganda

Beberapa negara mempunyai bilangan pola pengelompokan yang berubah-ubah dalam sistem penomboran mereka.

Sistem Penomboran India menggunakan format #, ##, ###. ##, di mana hanya pemisah pengelompokan pertama yang memegang tiga nombor, sementara yang lain memegang dua nombor.

Ini tidak mungkin dicapai dengan menggunakan kelas DecimalFormat , yang hanya menyimpan corak terkini yang dijumpai dari kiri ke kanan, dan menerapkannya ke seluruh nombor, mengabaikan corak pengelompokan sebelumnya.

Percubaan untuk menggunakan corak #, ##, ##, ##, ### akan menghasilkan kumpulan kembali ke #######, ### dan berakhir pada pengagihan semula ke #, ###, # ##, ###.

Untuk mencapai padanan pelbagai corak pengelompokan, perlu menulis kod manipulasi String kita sendiri , atau sebagai alternatif untuk mencuba DecimalFormat Icu4J , yang memungkinkan.

3.5. Mencampurkan Literasi Rentetan

Ada kemungkinan mencampurkan literal String dalam corak:

assertThat(new DecimalFormat("The # number") .format(d)) .isEqualTo("The 1234568 number"); 

Anda juga boleh menggunakan watak khas sebagai huruf String , dengan melarikan diri:

assertThat(new DecimalFormat("The '#' # number") .format(d)) .isEqualTo("The # 1234568 number"); 

4. Pemformatan Setempat

Banyak negara tidak menggunakan simbol bahasa Inggeris dan menggunakan koma sebagai pemisah perpuluhan dan titik sebagai pemisah pengelompokan.

Menjalankan corak #, ###. ## pada JVM dengan Locale Itali , misalnya, akan menghasilkan 1.234.567,89.

Walaupun ini boleh menjadi ciri i18n yang berguna dalam beberapa kes, pada yang lain kita mungkin ingin menerapkan format bebas JVM yang spesifik.

Inilah cara kita dapat melakukannya:

assertThat(new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.ENGLISH)).format(d)) .isEqualTo("1,234,567.89"); assertThat(new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.ITALIAN)).format(d)) .isEqualTo("1.234.567,89"); 

Jika Locale kita di berminat berada bukan di kalangan orang-orang yang diliputi oleh DecimalFormatSymbols pembina, kita boleh menentukan ia dengan getInstance kaedah:

Locale customLocale = new Locale("it", "IT"); assertThat(new DecimalFormat( "#,###.##", DecimalFormatSymbols.getInstance(customLocale)).format(d)) .isEqualTo("1.234.567,89");

5. Notasi Ilmiah

The Scientific Notation represents the product of a Mantissa and an exponent of ten. The number 1234567.89 can also be represented as 12.3456789 * 10^5 (the dot is shifted by 5 positions).

5.1. E-Notation

It's possible to express a number in Scientific Notation using the E pattern character representing the exponent of ten:

assertThat(new DecimalFormat("00.#######E0").format(d)) .isEqualTo("12.3456789E5"); assertThat(new DecimalFormat("000.000000E0").format(d)) .isEqualTo("123.456789E4"); 

We should keep in mind that the number of characters after the exponent is relevant, so if we need to express 10^12, we need E00 and not E0.

5.2. Engineering Notation

It's common to use a particular form of Scientific Notation called Engineering Notation, which adjusts results in order to be expressed as multiple of three, for example when using measuring units like Kilo (10^3), Mega (10^6), Giga (10^9), and so on.

We can enforce this kind of notation by adjusting the maximum number of integer digits (the characters expressed with the # and on the left of the decimal separator) so that it's higher than the minimum number (the one expressed with the 0) and higher than 1.

This forces the exponent to be a multiple of the maximum number, so for this use-case we want the maximum number to be three:

assertThat(new DecimalFormat("##0.######E0") .format(d)).isEqualTo("1.23456789E6"); assertThat(new DecimalFormat("###.000000E0") .format(d)).isEqualTo("1.23456789E6"); 

6. Parsing

Let's see how is possible to parse a String into a Number with the parse method:

assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ENGLISH)) .parse("1234567.89")) .isEqualTo(1234567.89); assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ITALIAN)) .parse("1.234.567,89")) .isEqualTo(1234567.89);

Oleh kerana nilai yang dikembalikan tidak disimpulkan dengan adanya pemisah perpuluhan, kita dapat menggunakan kaedah seperti .doubleValue () , .longValue () dari objek Number yang dikembalikan untuk menegakkan output primitif tertentu.

Kami juga dapat memperoleh BigDecimal seperti berikut:

NumberFormat nf = new DecimalFormat( "", new DecimalFormatSymbols(Locale.ENGLISH)); ((DecimalFormat) nf).setParseBigDecimal(true); assertThat(nf.parse("1234567.89")) .isEqualTo(BigDecimal.valueOf(1234567.89)); 

7. Keselamatan Benang

DecimalFormat tidak selamat untuk benang , oleh itu kita harus memberi perhatian khusus ketika berkongsi contoh yang sama antara utas.

8. Kesimpulannya

Kami telah melihat penggunaan utama kelas DecimalFormat , bersama dengan kelebihan dan kekurangannya .

Seperti biasa, kod sumber penuh tersedia di Github.