Menggabungkan teks dengan operator + masih praktis untuk dua-tiga nilai, tetapi kepraktisan itu cepat habis ketika satu kalimat membutuhkan sepuluh nilai sekaligus dengan posisi yang presisi. Untuk kebutuhan tersebut Java menyediakan pendekatan template: kita menulis pola string dengan format specifier sebagai lubang kosong, lalu mengirim data untuk mengisi lubang-lubang tersebut. Method String.format adalah pintu masuk paling umum, dan mesin di baliknya — class java.util.Formatter — adalah mesin yang sama yang akan kita pakai lagi pada printf dan System.console().readLine. Chapter ini membahas anatomi specifier, konversi yang paling sering dipakai, serta cara memakai ulang argumen.

Anatomi Format Specifier #

Setiap lubang kosong dalam template ditulis dengan pola berikut:

text
%[argument_index$][flags][width][.precision]conversion

Bagian yang wajib hanya tanda persen dan conversion — huruf yang menyatakan jenis data. Sisanya bersifat opsional dan akan kita bahas bertahap: indeks argumen di chapter ini, lebar serta presisi pada chapter Formatted Output. Berikut conversion yang paling sering dipakai:

SpecifierMenerimaHasil
%sobject apa punrepresentasi teks via String.valueOf
%dbilangan bulat (int, long, …)angka tanpa desimal
%fbilangan desimal (float, double)enam angka di belakang koma secara bawaan
%bboolean atau object apa puntrue/false
%ntanpa argumenpemisah baris platform

Membangun String dengan String.format #

String.format adalah method static pada class String yang mengembalikan string baru — template maupun argumen aslinya tidak berubah. Mari kita uji lima specifier sekaligus:

public class FormatSapaan {
    public static void main(String[] args) {
        String nama = "Budi";
        int umur = 17;
        double berat = 62.5;
        boolean lulus = true;

        String info = String.format(
                "Nama: %s | Umur: %d | Berat: %f | Berat (1 desimal): %.1f | Lulus: %b%n",
                nama, umur, berat, berat, lulus);
        System.out.print(info);
        System.out.println("Panjang info: " + info.length() + " karakter");
    }
}

Output yang Dihasilkan:

text
Nama: Budi | Umur: 17 | Berat: 62.500000 | Berat (1 desimal): 62.5 | Lulus: true
Panjang info: 81 karakter

Mari kita telaah bagian-bagian pentingnya:

  1. Baris 8-10 (String.format(template, args...)): argumen pertama adalah template; argumen kedua dan seterusnya adalah data yang mengisi specifier secara berurutan — %s diisi nama, %d diisi umur, dan seterusnya.
  2. Specifiers %f dan %.1f: keduanya menerima berat, tetapi %f tanpa presisi mencetak 62.500000 (enam digit bawaan), sedangkan %.1f membatasi menjadi satu digit desimal — 62.5.
  3. Specifier %b: menerima nilai boolean apa adanya; untuk object bukan boolean, nilai null dicetak sebagai false dan object apa pun yang tidak null dicetak sebagai true.
  4. Specifier %n: tidak mengonsumsi argumen; pemisah baris disisipkan langsung ke hasil.

Menyusun Template Multi-Baris #

Kekuatan template makin terasa saat hasil yang kita bangun berupa dokumen kecil multi-baris. Program berikut menyusun struk belanja, memaksa dua digit desimal untuk nominal uang, lalu mencetak string hasil tersebut — pembangunan dan pencetakan sepenuhnya terpisah:

public class StrukBelanja {
    public static void main(String[] args) {
        String nama = "Siti";
        int jumlah = 3;
        double hargaSatuan = 12500.0;
        double total = jumlah * hargaSatuan;

        String struk = String.format(
                "STRUK BELANJA%nPembeli : %s%nItem    : %d buku tulis%n"
                + "Harga   : %.2f per item%nTotal   : %.2f%nTerima kasih, %1$s!",
                nama, jumlah, hargaSatuan, total);
        System.out.println(struk);
    }
}

Output yang Dihasilkan:

text
STRUK BELANJA
Pembeli : Siti
Item    : 3 buku tulis
Harga   : 12500.00 per item
Total   : 37500.00
Terima kasih, Siti!

Dua hal patut digarisbawahi dari program tersebut. Pertama, operator + pada baris 9-10 hanya merangkai template di kode sumber agar baris kode tidak terlalu panjang — hasil gabungannya tetap satu template utuh bagi Formatter. Kedua, %1$s di akhir template memakai argumen pertama untuk kedua kalinya tanpa kita mengirim nama dua kali; string hasil disimpan dalam variabel struk sehingga dapat juga dikirim ke berkas, jaringan, atau komponen lain — bukan sekadar dicetak.

Menggunakan Ulang Argumen dengan Indeks #

Indeks argumen ditulis di antara % dan conversion dengan format N$, di mana N adalah posisi argumen mulai dari 1. Ada juga bentuk relatif %< yang berarti “argumen yang sama dengan specifier sebelumnya”:

public class IndeksArgumen {
    public static void main(String[] args) {
        String nama = "Siti";
        int skor = 90;

        System.out.println(String.format(
                "Halo %1$s, skor %2$d milik %1$s.", nama, skor));
        System.out.println(String.format(
                "Skor %2$d dicetak lebih dulu, nama %1$s belakangan.", nama, skor));
        System.out.println(String.format(
                "%s dan %<s mendapat nilai sama.", nama));
    }
}

Output yang Dihasilkan:

text
Halo Siti, skor 90 milik Siti.
Skor 90 dicetak lebih dulu, nama Siti belakangan.
Siti dan Siti mendapat nilai sama.

Baris pertama memakai %1$s dua kali sehingga argumen nama cukup dikirim sekali. Baris kedua membalik urutan pencetakan — %2$d lebih dulu — tanpa mengubah urutan argumen; trik ini berguna saat menerjemahkan kalimat yang tata bahasanya berbeda antarbahasa. Baris ketiga memperlihatkan bentuk relatif: %<s mengulang argumen yang dipakai specifier %s sebelumnya, sehingga hasilnya “Siti dan Siti”.

Memformat atau Menggabungkan #

Kapan + dan kapan String.format? Untuk dua nilai dengan pola sederhana, penggabungan + justru lebih ringkas dan mudah dibaca. Template menjadi pilihan ketika jumlah nilai banyak, ketika nilai yang sama dipakai berulang, ketika butuh presisi desimal tetap, atau ketika template akan disimpan sebagai konstanta yang dipisah dari data. Satu batasan penting: jika jumlah argumen tidak cocok dengan jumlah specifier, Formatter melempar exception saat program berjalan — compiler tidak memeriksa kecocokan tersebut. Setelah string hasil siap, langkah berikutnya sering kali tinggal mencetaknya; chapter Formatted Output membahas System.out.printf, pintu cepat yang memformat sekaligus mencetak dengan specifier yang sama persis.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

FormatSapaan.java

Unduh berkas
java
public class FormatSapaan {
    public static void main(String[] args) {
        String nama = "Budi";
        int umur = 17;
        double berat = 62.5;
        boolean lulus = true;

        String info = String.format(
                "Nama: %s | Umur: %d | Berat: %f | Berat (1 desimal): %.1f | Lulus: %b%n",
                nama, umur, berat, berat, lulus);
        System.out.print(info);
        System.out.println("Panjang info: " + info.length() + " karakter");
    }
}

IndeksArgumen.java

Unduh berkas
java
public class IndeksArgumen {
    public static void main(String[] args) {
        String nama = "Siti";
        int skor = 90;

        System.out.println(String.format(
                "Halo %1$s, skor %2$d milik %1$s.", nama, skor));
        System.out.println(String.format(
                "Skor %2$d dicetak lebih dulu, nama %1$s belakangan.", nama, skor));
        System.out.println(String.format(
                "%s dan %<s mendapat nilai sama.", nama));
    }
}

StrukBelanja.java

Unduh berkas
java
public class StrukBelanja {
    public static void main(String[] args) {
        String nama = "Siti";
        int jumlah = 3;
        double hargaSatuan = 12500.0;
        double total = jumlah * hargaSatuan;

        String struk = String.format(
                "STRUK BELANJA%nPembeli : %s%nItem    : %d buku tulis%n"
                + "Harga   : %.2f per item%nTotal   : %.2f%nTerima kasih, %1$s!",
                nama, jumlah, hargaSatuan, total);
        System.out.println(struk);
    }
}