Panduan Praktis untuk DecimalFormat

1. Ikhtisar

Pada artikel ini, kita akan menjelajahi kelas DecimalFormat beserta penggunaan praktisnya.

Ini adalah subclass NumberFormat , yang memungkinkan pemformatan representasi String angka desimal menggunakan pola yang telah ditentukan sebelumnya.

Ini juga dapat digunakan secara terbalik, untuk mengurai String menjadi angka.

2. Bagaimana cara kerjanya?

Untuk memformat angka, kita harus menentukan pola, yang merupakan urutan karakter khusus yang berpotensi tercampur dengan teks.

Ada 11 Karakter Pola Khusus, namun yang terpenting adalah:

  • 0 - mencetak digit jika disediakan, 0 jika tidak
  • # - mencetak digit jika disediakan, tidak ada yang lain
  • . - menunjukkan di mana harus meletakkan pemisah desimal
  • , - menunjukkan di mana harus meletakkan pemisah pengelompokan

Ketika pola diterapkan ke angka, aturan pemformatannya dijalankan, dan hasilnya dicetak sesuai dengan DecimalFormatSymbol dari Lokal JVM kami kecuali Lokal tertentu ditentukan.

Output contoh berikut ini berasal dari JVM yang berjalan pada Bahasa Inggris Lokal .

3. Pemformatan Dasar

Sekarang mari kita lihat keluaran mana yang dihasilkan saat memformat angka yang sama dengan pola berikut.

3.1. Desimal 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 bisa kita lihat, bagian integer tidak pernah dibuang, tidak peduli polanya lebih kecil dari angkanya.

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

Jika polanya lebih besar dari angkanya, angka nol akan ditambahkan, sementara hash dihilangkan, baik di bilangan bulat maupun di bagian desimal.

3.2. Pembulatan

Jika bagian desimal dari pola tidak dapat berisi seluruh presisi dari bilangan input, itu akan dibulatkan.

Di sini, bagian .89 telah dibulatkan menjadi .90, kemudian 0 telah dijatuhkan:

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

Di sini, bagian .89 telah dibulatkan menjadi 1.00, kemudian .00 telah dihilangkan dan 1 telah dijumlahkan menjadi 7:

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

Mode pembulatan default adalah HALF_EVEN, tetapi dapat disesuaikan melalui metode setRoundingMode .

3.3. Pengelompokan

Pemisah pengelompokan digunakan untuk menentukan sub-pola yang diulang secara otomatis:

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

3.4. Pola Pengelompokan Ganda

Beberapa negara memiliki sejumlah variabel pola pengelompokan dalam sistem penomorannya.

Sistem Penomoran India menggunakan format #, ##, ###. ##, di mana hanya pemisah pengelompokan pertama yang menampung tiga angka, sedangkan yang lainnya menampung dua angka.

Ini tidak mungkin dicapai dengan menggunakan kelas DecimalFormat , yang hanya mempertahankan pola terbaru yang ditemukan dari kiri ke kanan, dan menerapkannya ke seluruh bilangan, mengabaikan pola pengelompokan sebelumnya.

Upaya untuk menggunakan pola #, ##, ##, ##, ### akan menghasilkan pengelompokan ulang ke #######, ### dan diakhiri dengan redistribusi ke #, ###, # ##, ###.

Untuk mencapai beberapa pencocokan pola pengelompokan, perlu untuk menulis kode manipulasi String kita sendiri , atau sebagai alternatif untuk mencoba DecimalFormat Icu4J , yang memungkinkannya.

3.5. Mencampur Literal String

Ini mungkin untuk mencampur literal String dalam pola:

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

Ini juga memungkinkan untuk menggunakan karakter khusus sebagai literal String , melalui pelolosan:

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

4. Pemformatan Lokal

Banyak negara tidak menggunakan simbol bahasa Inggris dan menggunakan koma sebagai pemisah desimal dan titik sebagai pemisah pengelompokan.

Menjalankan pola #, ###. ## pada JVM dengan Lokal Italia , misalnya, akan menghasilkan 1.234.567,89.

Meskipun ini bisa menjadi fitur i18n yang berguna dalam beberapa kasus, di kasus lain kami mungkin ingin menerapkan format tertentu yang tidak bergantung JVM.

Inilah cara kami 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 Lokal yang kita minati tidak termasuk yang dicakup oleh konstruktor DecimalFormatSymbols , kita dapat menentukannya dengan metode getInstance :

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

5. Notasi Ilmiah

Notasi Ilmiah mewakili produk dari Mantissa dan eksponen sepuluh. Angka 1234567.89 juga dapat direpresentasikan sebagai 12.3456789 * 10 ^ 5 (titik digeser oleh 5 posisi).

5.1. E -Notasi

Ada kemungkinan untuk mengekspresikan bilangan dalam Notasi Ilmiah menggunakan karakter pola E yang mewakili eksponen sepuluh:

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

Kita harus ingat bahwa jumlah karakter setelah eksponen relevan, jadi jika kita perlu mengekspresikan 10 ^ 12, kita membutuhkan E00 dan bukan E0 .

5.2. Notasi Teknik

Merupakan hal yang umum untuk menggunakan bentuk Notasi Ilmiah tertentu yang disebut Notasi Teknik, yang menyesuaikan hasil agar dapat dinyatakan sebagai kelipatan tiga, misalnya saat menggunakan satuan pengukuran seperti Kilo (10 ^ 3), Mega (10 ^ 6), Giga ( 10 ^ 9), dan seterusnya.

Kita dapat menerapkan jenis notasi ini dengan menyesuaikan jumlah maksimum digit bilangan bulat (karakter yang diekspresikan dengan # dan di kiri pemisah desimal) sehingga lebih tinggi dari angka minimum (yang diekspresikan dengan 0) dan lebih tinggi dari 1.

Ini memaksa eksponen menjadi kelipatan dari bilangan maksimum, jadi untuk kasus penggunaan ini kita ingin bilangan maksimum menjadi tiga:

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

6. Parsing

Mari kita lihat bagaimana mungkin untuk mengurai String menjadi Number dengan metode parse:

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);

Karena nilai yang dikembalikan tidak disimpulkan dengan adanya pemisah desimal, kita bisa menggunakan metode seperti .doubleValue () , .longValue () dari objek Number yang dikembalikan untuk menerapkan primitif tertentu dalam keluaran.

Kami juga bisa mendapatkan BigDecimal sebagai berikut:

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

7. Keamanan Benang

DecimalFormat tidak aman untuk thread , jadi kita harus memberikan perhatian khusus saat berbagi instance yang sama antar thread.

8. Kesimpulan

Kami telah melihat penggunaan utama kelas DecimalFormat , bersama dengan kekuatan dan kelemahannya .

Seperti biasa, kode sumber lengkap tersedia di Github.