Angka 1234567.891 itu mutlak, tetapi cara membacanya tidak: pembaca Indonesia melihat 1.234.567,891, pembaca Amerika melihat 1,234,567.891, dan keduanya sama-sama merasa format lawannya membingungkan. Java menyelesaikan persoalan ini dengan class Locale — penanda identitas bahasa dan wilayah — serta dua alat pemformatan di atasnya: NumberFormat untuk format baku dan DecimalFormat untuk pola kustom. Chapter ini membahas ketiganya secara berurutan, melengkapi flag , pada printf yang telah kita lihat pada chapter sebelumnya.
Apa itu Locale #
Object Locale membawa dua informasi utama: kode bahasa dua huruf (id, en, ja) dan kode negara dua huruf (ID, US, JP). Kombinasi keduanya menentukan konvensi yang dipakai pustaka Java saat memformat angka, mata uang, tanggal, hingga urutan kata. Sejak Java 19, pembuatan Locale disarankan lewat method Locale.of(language, country); bentuk lamanya, new Locale("id", "ID"), tetap sah tetapi ditandai deprecated.
import java.util.Locale;
public class KenalLocale {
public static void main(String[] args) {
Locale id = Locale.of("id", "ID");
Locale us = Locale.US;
System.out.println("Locale default : " + Locale.getDefault());
System.out.println("Tag bahasa : " + id.toLanguageTag());
System.out.println("Kode bahasa : " + id.getLanguage());
System.out.println("Kode negara : " + id.getCountry());
System.out.println("Nama (dalam id): " + id.getDisplayName(id));
System.out.println("Nama (dalam en): " + id.getDisplayName(us));
}
}Output yang Dihasilkan:
Locale default : en_US
Tag bahasa : id-ID
Kode bahasa : id
Kode negara : ID
Nama (dalam id): Indonesia (Indonesia)
Nama (dalam en): Indonesian (Indonesia)Method getDisplayName menarik perhatian: hasilnya mengikuti argumennya — nama locale id-ID ditampilkan sebagai “Indonesia (Indonesia)” ketika diterjemahkan dalam bahasa Indonesia, dan “Indonesian (Indonesia)” dalam bahasa Inggris.
NumberFormat untuk Angka, Persen, dan Uang #
NumberFormat adalah class pabrik: kita tidak menulis pola, melainkan meminta format siap pakai sesuai jenis data — getNumberInstance, getIntegerInstance, getPercentInstance, dan getCurrencyInstance — masing-masing dengan Locale sebagai argumen:
import java.text.NumberFormat;
import java.util.Locale;
public class FormatLocale {
public static void main(String[] args) {
double harga = 1234567.891;
Locale id = Locale.of("id", "ID");
Locale us = Locale.US;
NumberFormat angkaId = NumberFormat.getNumberInstance(id);
NumberFormat angkaUs = NumberFormat.getNumberInstance(us);
System.out.println("Angka id_ID : " + angkaId.format(harga));
System.out.println("Angka en_US : " + angkaUs.format(harga));
NumberFormat bulatId = NumberFormat.getIntegerInstance(id);
System.out.println("Bulat id_ID : " + bulatId.format(harga));
NumberFormat persenId = NumberFormat.getPercentInstance(id);
NumberFormat persenUs = NumberFormat.getPercentInstance(us);
System.out.println("Persen id_ID : " + persenId.format(0.875));
System.out.println("Persen en_US : " + persenUs.format(0.875));
NumberFormat uangId = NumberFormat.getCurrencyInstance(id);
NumberFormat uangUs = NumberFormat.getCurrencyInstance(us);
System.out.println("Uang id_ID : " + uangId.format(12500000));
System.out.println("Uang en_US : " + uangUs.format(12500000));
}
}Output yang Dihasilkan:
Angka id_ID : 1.234.567,891
Angka en_US : 1,234,567.891
Bulat id_ID : 1.234.568
Persen id_ID : 88%
Persen en_US : 88%
Uang id_ID : Rp12.500.000,00
Uang en_US : $12,500,000.00Empat fakta penting terbaca langsung dari hasil tersebut. Pertama, format angka id_ID memakai titik sebagai pemisah ribuan dan koma sebagai desimal — kebalikan dari en_US. Kedua, getIntegerInstance membulatkan nilai desimal menjadi bilangan bulat terdekat (1234567.891 menjadi 1.234.568). Ketiga, getPercentInstance mengalikan nilai dengan 100 lalu menambah tanda persen, dengan pembulatan ke persen utuh secara bawaan — 0.875 menjadi 88%, bukan 87,5%; jumlah digit pecahan dapat diatur lewat setMinimumFractionDigits. Keempat, format mata uang menambahkan simbol sesuai data CLDR yang dibundel JDK: Rp untuk Indonesia dan $ untuk Amerika Serikat, lengkap dengan dua digit desimal khas nilai uang.
DecimalFormat dengan Pola Kustom #
Ketika format baku tidak cukup — misalnya butuh prefix “Rp” tanpa desimal, atau jumlah digit tetap — kita turun ke DecimalFormat dan menulis pola sendiri. Dua karakter inti pola: # berarti “tampilkan digit jika ada”, 0 berarti “digit wajib tampil, tambahkan nol bila kosong”. Posisi koma dan titik pada pola adalah penanda tempat, bukan karakter keluaran:
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class DecimalFormatPattern {
public static void main(String[] args) {
double harga = 1234567.891;
double berat = 62.5;
DecimalFormatSymbols simbolId =
DecimalFormatSymbols.getInstance(Locale.of("id", "ID"));
DecimalFormat polaDefault = new DecimalFormat("#,###.##");
DecimalFormat polaId = new DecimalFormat("#,###.##", simbolId);
System.out.println("A #,###.## default : " + polaDefault.format(harga));
System.out.println("B #,###.## id_ID : " + polaId.format(harga));
DecimalFormat duaDesimal = new DecimalFormat("#.00", simbolId);
System.out.println("C #.00 id_ID : " + duaDesimal.format(berat));
DecimalFormat rataNol = new DecimalFormat("000.000", simbolId);
System.out.println("D 000.000 id_ID : " + rataNol.format(berat));
DecimalFormat rupiah = new DecimalFormat("Rp#,###.00", simbolId);
System.out.println("E Rp#,###.00 id_ID : " + rupiah.format(harga));
}
}Output yang Dihasilkan:
A #,###.## default : 1,234,567.89
B #,###.## id_ID : 1.234.567,89
C #.00 id_ID : 62,50
D 000.000 id_ID : 062,500
E Rp#,###.00 id_ID : Rp1.234.567,89Perhatikan baris A dan B: polanya sama persis — #,###.## — tetapi hasilnya berbeda karena DecimalFormat tanpa argumen simbol memakai DecimalFormatSymbols milik Locale default (en_US di lingkungan ini), sedangkan baris B dipasok simbol id_ID. Karakter , dan . di dalam pola hanya menandai posisi pemisah ribuan dan desimal; karakter nyata yang dicetak ditentukan oleh simbol.
Sisa baris memperlihatkan ragam lainnya: pola #.00 memaksa dua digit desimal (62,50 dengan simbol id), pola 000.000 menjaga enam digit dengan nol penambah (062,500), dan teks biasa seperti Rp di awal pola ikut tercetak sebagai prefix — jalan pintas untuk label mata uang tanpa NumberFormat.
Memilih Pendekatan yang Tepat #
| Kebutuhan | Alat yang pas |
|---|---|
| Pemisah ribuan sekali cetak | flag , pada printf |
| Format angka/uang/persen baku per negara | NumberFormat + Locale |
| Lebar kolom, presisi, perataan | printf dengan width dan precision |
| Pola digit benar-benar kustom | DecimalFormat + DecimalFormatSymbols |
Satu catatan praktis untuk kode server: object NumberFormat dan DecimalFormat tidak aman dipakai bersama banyak thread — dokumentasi Oracle menyarankan membuat instance baru per thread ketika format dipakai secara konkuren. Untuk program kecil satu thread seperti contoh kita, hal tersebut tidak berpengaruh. Sejauh ini seluruh data masuk lewat keyboard saat program berjalan; bagaimana jika data justru diberikan sejak program diluncurkan? Chapter Membaca Argumen Command Line membahas array args pada method main.
Referensi #
- Oracle: Locale (Java SE 25 API)
- Oracle: NumberFormat (Java SE 25 API)
- Oracle: DecimalFormat (Java SE 25 API)
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
DecimalFormatPattern.java
Unduh berkasimport java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class DecimalFormatPattern {
public static void main(String[] args) {
double harga = 1234567.891;
double berat = 62.5;
DecimalFormatSymbols simbolId =
DecimalFormatSymbols.getInstance(Locale.of("id", "ID"));
DecimalFormat polaDefault = new DecimalFormat("#,###.##");
DecimalFormat polaId = new DecimalFormat("#,###.##", simbolId);
System.out.println("A #,###.## default : " + polaDefault.format(harga));
System.out.println("B #,###.## id_ID : " + polaId.format(harga));
DecimalFormat duaDesimal = new DecimalFormat("#.00", simbolId);
System.out.println("C #.00 id_ID : " + duaDesimal.format(berat));
DecimalFormat rataNol = new DecimalFormat("000.000", simbolId);
System.out.println("D 000.000 id_ID : " + rataNol.format(berat));
DecimalFormat rupiah = new DecimalFormat("Rp#,###.00", simbolId);
System.out.println("E Rp#,###.00 id_ID : " + rupiah.format(harga));
}
}
FormatLocale.java
Unduh berkasimport java.text.NumberFormat;
import java.util.Locale;
public class FormatLocale {
public static void main(String[] args) {
double harga = 1234567.891;
Locale id = Locale.of("id", "ID");
Locale us = Locale.US;
NumberFormat angkaId = NumberFormat.getNumberInstance(id);
NumberFormat angkaUs = NumberFormat.getNumberInstance(us);
System.out.println("Angka id_ID : " + angkaId.format(harga));
System.out.println("Angka en_US : " + angkaUs.format(harga));
NumberFormat bulatId = NumberFormat.getIntegerInstance(id);
System.out.println("Bulat id_ID : " + bulatId.format(harga));
NumberFormat persenId = NumberFormat.getPercentInstance(id);
NumberFormat persenUs = NumberFormat.getPercentInstance(us);
System.out.println("Persen id_ID : " + persenId.format(0.875));
System.out.println("Persen en_US : " + persenUs.format(0.875));
NumberFormat uangId = NumberFormat.getCurrencyInstance(id);
NumberFormat uangUs = NumberFormat.getCurrencyInstance(us);
System.out.println("Uang id_ID : " + uangId.format(12500000));
System.out.println("Uang en_US : " + uangUs.format(12500000));
}
}
KenalLocale.java
Unduh berkasimport java.util.Locale;
public class KenalLocale {
public static void main(String[] args) {
Locale id = Locale.of("id", "ID");
Locale us = Locale.US;
System.out.println("Locale default : " + Locale.getDefault());
System.out.println("Tag bahasa : " + id.toLanguageTag());
System.out.println("Kode bahasa : " + id.getLanguage());
System.out.println("Kode negara : " + id.getCountry());
System.out.println("Nama (dalam id): " + id.getDisplayName(id));
System.out.println("Nama (dalam en): " + id.getDisplayName(us));
}
}