Chapter String Immutability menutup dengan persoalan yang mengganjal: merangkai teks dengan operator + di dalam perulangan menghasilkan tumpukan objek String sementara karena setiap penggabungan menyalin seluruh isi lama. Java menyediakan class penolong khusus untuk pekerjaan tersebut — java.lang.StringBuilder, wadah teks yang bisa dimodifikasi di tempat tanpa salin-menyalin. Chapter ini mempraktikkan operasi inti StringBuilder (append, insert, delete, reverse), menjelaskan mekanisme kapasitas internalnya, lalu menutup dengan perbandingan hasil versus operator + agar perbedaan keduanya terlihat dari sisi pembaca kode.

Wadah Teks yang Bisa Diubah #

StringBuilder menyimpan karakter di larik internal yang bisa ditumbuhkan ukurannya. Berbeda dengan String, method append tidak mengembalikan salinan — method menambahkan karakter ke larik yang sama lalu mengembalikan referensi StringBuilder itu sendiri (pola fluent yang memungkinkan pemanggilan berantai). Hasil akhir diambil dengan toString() begitu rangkaian selesai.

Constructor StringBuilder punya dua varian berguna selain bentuk kosong: new StringBuilder("teks awal") memulai dari isi tertentu, dan new StringBuilder(100) menyiapkan kapasitas 100 karakter sejak awal — berguna bila perkiraan ukuran akhir sudah diketahui, karena realokasi larik internal bisa dihindari sepenuhnya. Perlu mengubah karakter tunggal? Method setCharAt(indeks, karakter) menimpa satu posisi tanpa membangun ulang apa pun, dan setLength(n) memotong atau memperpanjang isi larik.

public class PembangunTeks {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        System.out.println("Kapasitas awal : " + sb.capacity());

        sb.append("Belajar");
        sb.append(" ");
        sb.append("Java");
        System.out.println("Isi            : " + sb);
        System.out.println("Panjang        : " + sb.length());
        System.out.println("Kapasitas kini : " + sb.capacity());

        sb.insert(8, "bersama ");
        System.out.println("Setelah insert : " + sb);
        System.out.println("Kapasitas tumbuh: " + sb.capacity());

        sb.delete(8, 16);
        System.out.println("Setelah delete : " + sb);

        sb.reverse();
        System.out.println("Setelah reverse: " + sb);

        String hasil = sb.toString();
        System.out.println("toString       : " + hasil);
    }
}

Output yang Dihasilkan:

text
Kapasitas awal : 16
Isi            : Belajar Java
Panjang        : 12
Kapasitas kini : 16
Setelah insert : Belajar bersama Java
Kapasitas tumbuh: 34
Setelah delete : Belajar Java
Setelah reverse: avaJ rajaleB
toString       : avaJ rajaleB

Mari kita telaah baris-baris kode di atas:

  1. Baris 3 (new StringBuilder()): membuat wadah kosong dengan kapasitas bawaan 16 karakter — kapasitas adalah ruang larik internal yang sudah disiapkan, bukan jumlah karakter nyata.
  2. Baris 6-8 (tiga append): ketiga pemanggilan menempelkan teks pada larik yang sama. Setelah 12 karakter terisi, length() bernilai 12 sedangkan capacity() tetap 16 — masih ada ruang sisa, jadi tidak ada realokasi.
  3. Baris 13-14 (insert(8, "bersama ")): menyisipkan teks mulai indeks 8 tepat sebelum huruf J, menggeser karakter sisanya ke kanan. Panjang kini 21, melebihi kapasitas 16, sehingga StringBuilder mengalokasikan ulang larik dengan rumus 2 × kapasitas + 2 — kapasitas melonjak menjadi 34.
  4. Baris 17-18 (delete(8, 16)): membuang karakter indeks 8 hingga sebelum 16 — tepat delapan karakter "bersama " — mengembalikan isi ke "Belajar Java". Kapasitas tidak menyusut setelah menyusutnya isi; realokasi hanya arah bertambah.
  5. Baris 20-21 (reverse): membalik urutan karakter di tempat menjadi "avaJ rajaleB". Operasi klasik yang mahal bila dilakukan dengan String (salin bolak-balik), murah di sini.
  6. Baris 23-24 (toString): momen konversi — isi larik dibekukan menjadi String immutable untuk dipakai selanjutnya. Pola pemakaian StringBuilder selalu diakhiri langkah ini.

Perbandingan dengan Operator + dalam Perulangan #

Contoh berikut merangkai angka 1 sampai 10 dua cara: operator + pada String, dan append pada StringBuilder. Hasil akhirnya identik — perbedaannya ada pada jumlah objek yang tercipta di belakang layar.

public class RangkaiEfisien {
    public static void main(String[] args) {
        int jumlah = 10;

        String denganString = "";
        for (int i = 1; i <= jumlah; i++) {
            denganString = denganString + i + " ";
        }

        StringBuilder pembangun = new StringBuilder();
        for (int i = 1; i <= jumlah; i++) {
            pembangun.append(i).append(" ");
        }
        String denganBuilder = pembangun.toString();

        System.out.println("String        : [" + denganString + "]");
        System.out.println("StringBuilder : [" + denganBuilder + "]");
        System.out.println("Isi sama?     : " + denganString.equals(denganBuilder));
    }
}

Output yang Dihasilkan:

text
String        : [1 2 3 4 5 6 7 8 9 10 ]
StringBuilder : [1 2 3 4 5 6 7 8 9 10 ]
Isi sama?     : true

Bedah ringkasnya: loop pertama (baris 5-7) membuat String baru di tiap iterasi — sepuluh objek, yang terakhir menyimpan seluruh hasil. Loop kedua (baris 9-12) menambah angka ke larik internal yang sama; pembangun.append(i).append(" ") adalah pemanggilan berantai yang sah karena append mengembalikan StringBuilder yang sama. Output membuktikan isi kedua hasil persis sama, namun versi StringBuilder hanya membutuhkan satu wadah kerja plus satu String akhir dari toString().

StringBuilder menuntaskan pekerjaan merangkai teks secara efisien. Nama yang mirip akan segera kita jumpai — StringBuffer, saudara tua dengan API yang sama persis namun jiwa yang berbeda di dunia multi-thread.

Referensi #

Berkas Sumber

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

PembangunTeks.java

Unduh berkas
java
public class PembangunTeks {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        System.out.println("Kapasitas awal : " + sb.capacity());

        sb.append("Belajar");
        sb.append(" ");
        sb.append("Java");
        System.out.println("Isi            : " + sb);
        System.out.println("Panjang        : " + sb.length());
        System.out.println("Kapasitas kini : " + sb.capacity());

        sb.insert(8, "bersama ");
        System.out.println("Setelah insert : " + sb);
        System.out.println("Kapasitas tumbuh: " + sb.capacity());

        sb.delete(8, 16);
        System.out.println("Setelah delete : " + sb);

        sb.reverse();
        System.out.println("Setelah reverse: " + sb);

        String hasil = sb.toString();
        System.out.println("toString       : " + hasil);
    }
}

RangkaiEfisien.java

Unduh berkas
java
public class RangkaiEfisien {
    public static void main(String[] args) {
        int jumlah = 10;

        String denganString = "";
        for (int i = 1; i <= jumlah; i++) {
            denganString = denganString + i + " ";
        }

        StringBuilder pembangun = new StringBuilder();
        for (int i = 1; i <= jumlah; i++) {
            pembangun.append(i).append(" ");
        }
        String denganBuilder = pembangun.toString();

        System.out.println("String        : [" + denganString + "]");
        System.out.println("StringBuilder : [" + denganBuilder + "]");
        System.out.println("Isi sama?     : " + denganString.equals(denganBuilder));
    }
}