String template dengan $ sangat cocok untuk interpolasi sederhana, tetapi saat kita perlu kontrol presisi — lebar kolom tetap, jumlah desimal, padding dengan nol, atau alignment kiri/kanan — kita perlu format gaya C. Kotlin mewarisi mekanisme ini dari Java melalui String.format() dan extension function .format() pada String. Keduanya memanfaatkan java.util.Formatter di balik layar, sehingga seluruh specifier standar tersedia. Chapter ini membongkar specifier yang paling umum, lalu menunjukkan cara membangun tabel terformat yang rapi.

String.format() vs .format() #

Terdapat dua cara memanggil string formatting di Kotlin:

kotlin Contoh: dua cara format
val nama = "Budi"
val umur = 25

// Cara 1: companion function pada String
val s1 = String.format("Nama: %s, Umur: %d", nama, umur)

// Cara 2: extension function pada String
val s2 = "Nama: %s, Umur: %d".format(nama, umur)

println(s1)
println(s2)

Kedua cara menghasilkan output identik. Extension function .format() lebih idiomatis di Kotlin karena lebih ringkas dan memungkinkan chaining. Keduanya menerima argumen vararg Any?, sehingga jumlah argumen dapat fleksibel selama cocok dengan jumlah placeholder di format string.

Format Specifier Umum #

Setiap specifier dimulai dengan % dan diikuti konversi. Tabel berikut merangkum specifier yang paling sering dipakai:

SpecifierTipe argumenOutput contoh
%sString, Any"Budi"
%dInt, Long, Short, Byte25
%fFloat, Double175.500000 (default 6 desimal)
%eFloat, Double1.755000e+02 (notasi ilmiah)
%xbilangan bulatff (255 dalam heksadesimal lowercase)
%Xbilangan bulatFF (huruf besar)
%obilangan bulat377 (oktal)
%bBooleantrue / false
%cChar, Int (kode Unicode)A
%n(tanpa argumen)newline sesuai platform
%%(tanpa argumen)tanda persen literal %

Contoh String Formatting #

kotlin
fun main() {
    val nama = "Budi"
    val umur = 25
    val tinggi = 175.5
    val aktif = true

    println(String.format("Nama: %s", nama))
    println("Umur: %d tahun".format(umur))
    println("Tinggi: %.2f cm".format(tinggi))
    println("Aktif: %b".format(aktif))

    val hex = 255
    println("Hex: %x".format(hex))
    println("HEX: %X".format(hex))
    println("Octal via o: %o".format(8))
    println("Char: %c".format('A'))

    println("%-10s|%10s".format("kiri", "kanan"))
    println("%5d dan %05d".format(42, 42))
    println("Persen: %.1f%%".format(99.5))

    val baris = "| %-15s | %3d | %8.2f |%n"
    System.out.printf(baris, "Apel", 10, 15.5)
    System.out.printf(baris, "Jeruk", 3, 4.25)
    System.out.printf(baris, "Mangga", 100, 250.0)

    println("---")
    val format = "Halo %s, Anda berumur %d tahun"
    println(format.format("Siti", 30))
}

Output yang Dihasilkan:

text
Nama: Budi
Umur: 25 tahun
Tinggi: 175.50 cm
Aktif: true
Hex: ff
HEX: FF
Octal via o: 10
Char: A
kiri      |     kanan
   42 dan 00042
Persen: 99.5%
| Apel            |  10 |    15.50 |
| Jeruk           |   3 |     4.25 |
| Mangga          | 100 |   250.00 |
---
Halo Siti, Anda berumur 30 tahun

Mari kita telaah baris-baris kode di atas:

  1. Baris 6 (String.format("Nama: %s", nama)): pemanggilan companion function. Placeholder %s diganti dengan toString() dari argumen nama bertipe String. Untuk tipe non-primitif, %s selalu memanggil toString().
  2. Baris 7 ("Umur: %d tahun".format(umur)): extension function pada String. Placeholder %d mengharapkan argumen bilangan bulat (Int, Long, Short, Byte). Argumen umur bertipe Int, cocok.
  3. Baris 8 ("%.2f"): specifier %f dengan flag .2 membatasi jumlah desimal menjadi 2. Tanpa flag, %f default menampilkan 6 angka di belakang koma.
  4. Baris 9 ("%b"): specifier untuk Boolean. Output berupa true atau false lowercase, berbeda dengan Boolean.toString() di Kotlin yang juga lowercase, namun %B akan menghasilkan huruf besar TRUE.
  5. Baris 11–13 (%x, %X, %o): bilangan bulat 255 ditampilkan dalam heksadesimal (ff/FF) dan oktal (377). Specifier %X memaksa huruf besar untuk digit A-F.
  6. Baris 14 ("%c"): specifier untuk karakter. Diberi argumen Char 'A', ditampilkan apa adanya. Argumen Int juga valid — akan dikonversi ke karakter Unicode dengan kode tersebut.
  7. Baris 16 ("%-10s|%10s"): kombinasi alignment dan width. %-10s artinya string di-padding ke lebar 10 karakter, rata kiri (tanda -). %10s di-padding ke lebar 10, rata kanan (default tanpa -). Karakter padding default adalah spasi.
  8. Baris 17 ("%5d dan %05d"): %5d mem-padding angka 42 menjadi 5 karakter dengan spasi ( 42). %05d mem-padding dengan nol (00042).
  9. Baris 18 ("%.1f%%"): specifier %% menampilkan tanda persen literal. Output: Persen: 99.5%. Catatan: % diikuti % bukan placeholder argumen.
  10. Baris 20–24 (System.out.printf): pemanggilan printf pada System.out (Java interop). printf tidak mengembalikan String melainkan PrintStream dan langsung menulis ke stdout. Placeholder %-15s, %3d, %8.2f, dan %n menghasilkan kolom yang rapi.
  11. Baris 26–28: variabel format bertipe String menyimpan format string. Kita dapat memanggil .format(...) kapan pun dibutuhkan, bahkan beberapa kali dengan argumen berbeda.

Width, Precision, dan Flag #

Sintaks lengkap specifier adalah:

text
%[flag][width][.precision]conversion
KomponenFungsi
Flag -Rata kiri (default rata kanan)
Flag 0Padding dengan nol (hanya untuk angka)
Flag +Tampilkan tanda + untuk angka positif
Flag ,Tambahkan pemisah grup (locale-dependent)
Flag (Bungkus angka negatif dalam tanda kurung
WidthLebar minimum total field
PrecisionUntuk %f: jumlah desimal. Untuk %s: panjang maksimum string

Contoh kombinasi:

text
%8.2f   → "  175.50" (lebar 8, 2 desimal, rata kanan)
%-8.2f  → "175.50  " (lebar 8, 2 desimal, rata kiri)
%+8.2f  → " +175.50" (tampilkan tanda +)
%08.2f  → "00175.50" (padding dengan nol)
%,.2f   → "1,234,567.89" (pemisah grup, locale default)

printf untuk Tabel Terformat #

Pola paling umum untuk tabel terformat adalah menyimpan format baris di satu variabel, lalu memanggilnya berulang:

kotlin Contoh: tabel terformat
fun main() {
    val baris = "| %-15s | %3d | %8.2f |%n"
    System.out.printf(baris, "Apel", 10, 15.5)
    System.out.printf(baris, "Jeruk", 3, 4.25)
    System.out.printf(baris, "Mangga", 100, 250.0)
}

Karena lebar kolom tetap, tabel tetap rapi meskipun konten memiliki panjang yang berbeda. Pola ini banyak dipakai di program CLI yang melaporkan metrik atau data tabular.

Referensi Lanjutan #

Dengan penguasaan specifier dasar, kita siap beranjak ke topik yang lebih spesifik: numeric formatting — penggunaan flag grup, padding nol, dan tanda plus untuk angka.