Eğitim Portalı/Java/StringBuilder Sınıfı
Java01-java/53-stringbuilder

StringBuilder Sınıfı

String Java'da değişmezdir (immutable): bir kez oluşturulan metin asla değişmez; "değiştirme" gibi görünen her işlem aslında yeni bir String üretir. Bu, güvenlik ve thread-güvenliği için harikadır ama bir metni parça…

StringBuilder Sınıfı

String Java'da değişmezdir (immutable): bir kez oluşturulan metin asla değişmez; "değiştirme" gibi görünen her işlem aslında yeni bir String üretir. Bu, güvenlik ve thread-güvenliği için harikadır ama bir metni parça parça inşa ederken ciddi bir performans sorununa dönüşür. İşte StringBuilder tam da bunun için vardır: değiştirilebilir bir metin tamponu.

String neden yetmez?

String s = "";
for (int i = 0; i < 50000; i++) s += i;   // her tur YENİ String kopyalar -> O(n^2)

Her +=, eski içeriği yeni bir String'e kopyalayıp yenisini ekler. N tur için bu, toplamda O(n²) iştir — büyük N'de fark edilir biçimde yavaşlar ve bellek çöpü üretir.

StringBuilder: değiştirilebilir tampon

StringBuilder aynı, gerektiğinde büyüyen tampon üzerinde çalışır; kopyalama yapmaz:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 50000; i++) sb.append(i);  // O(n)
String sonuc = sb.toString();

Örnek 2 (./Ornek2.java) iki yaklaşımı ölçer; aradaki fark büyük N'de çarpıcıdır.

İncelik: Tek satırlık sabit birleştirmelerde (a + b + c) derleyici zaten arka planda StringBuilder kullanır; orada elle yazmana gerek yok. Asıl fark döngülerde ortaya çıkar — döngüde metin kuruyorsan StringBuilder kullan.

Temel metotlar

sb.append(x);            // sona ekle (her tipi kabul eder: String, int, char, ...)
sb.insert(pos, x);       // konuma ekle
sb.delete(from, to);     // aralığı sil
sb.deleteCharAt(i);
sb.replace(from, to, s); // aralığı değiştir
sb.reverse();            // ters çevir
sb.setCharAt(i, c); sb.charAt(i); sb.length();
sb.toString();           // String'e çevir

Metotların çoğu StringBuilder'ın kendisini döndürür; bu yüzden zincirleme (method chaining) yazılır: sb.append("[").append(x).append("]"). Örnek 1 (./Ornek1.java) tüm bu işlemleri ve zincirlemeyi gösterir.

StringBuilder vs StringBuffer

İkisi aynı API'ye sahiptir; tek fark:

StringBuilderStringBuffer
Thread-safeHayırEvet (metotlar synchronized)
HızDaha hızlıDaha yavaş (kilit yükü)
Ne zamanVarsayılan (tek thread)Paylaşılan değiştirilebilir metin (nadir)

Kural: Neredeyse her zaman StringBuilder kullan. StringBuffer'ı yalnızca aynı tampon birden çok thread tarafından gerçekten paylaşılıyorsa düşün (çok nadir; genelde tasarımı değiştirmek daha iyidir).

Modern alternatifler

  • String.join(",", liste): Bir koleksiyonu ayraçla birleştirmek için.
  • Collectors.joining(",", "[", "]"): Stream'de birleştirme.
  • String.format / metin blokları: Biçimli/çok satırlı sabit metinler için.

Bunlar okunabilirlik sağlar; ama yoğun, koşullu, döngüsel metin inşasında hâlâ StringBuilder en esnek ve en hızlı yoldur.

Özet

String'in değişmezliğinin döngüsel metin inşasında neden yavaş olduğunu; StringBuilder'ın değiştirilebilir tamponla bunu nasıl çözdüğünü (Örnek 2); temel metotları ve zincirlemeyi (Örnek 1) ve StringBuffer ayrımını öğrendik. "Döngüde metin kuruyorsan StringBuilder" altın kuraldır. Bu, Class References bölümünün bu turdaki kısmını tamamlıyor.

Kod Örnekleri(2)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: StringBuilder — değiştirilebilir metin: append/insert/delete/reverse/replace.
2// Çalıştırma: java Ornek1.java
3public class Ornek1 {
4
5    public static void main(String[] args) {
6        StringBuilder sb = new StringBuilder("Merhaba");
7
8        // append: sona ekleme (her tipi kabul eder)
9        sb.append(" ").append("Dünya").append('!').append(" ").append(2026);
10        System.out.println("append: " + sb);
11
12        // insert: belirli konuma ekleme
13        sb.insert(7, ", güzel");
14        System.out.println("insert: " + sb);
15
16        // delete / deleteCharAt
17        sb.delete(7, 14);           // eklediğimiz ", güzel"i sil
18        System.out.println("delete: " + sb);
19
20        // replace
21        sb.replace(0, 7, "Selam");
22        System.out.println("replace: " + sb);
23
24        // reverse, length, charAt, setCharAt
25        StringBuilder ters = new StringBuilder("abcde").reverse();
26        System.out.println("reverse: " + ters);
27
28        // Method chaining (akıcı arayüz): her metot sb'yi döndürür
29        String sonuc = new StringBuilder()
30                .append("[").append("a").append(",").append("b").append("]")
31                .toString();
32        System.out.println("chaining: " + sonuc);
33
34        System.out.println("""
35
36                --- StringBuilder ---
37                String DEĞİŞMEZDİR (immutable): her "+" yeni bir String nesnesi yaratır.
38                StringBuilder DEĞİŞTİRİLEBİLİR: aynı tampon üzerinde ekler/siler/değiştirir -> verimli.
39                append/insert/delete/replace/reverse/setCharAt; toString() ile String'e çevrilir.
40                Metotlar sb'yi döndürdüğü için zincirleme (chaining) yazılır.""");
41    }
42}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: Neden StringBuilder? — döngüde String birleştirme vs StringBuilder (ölçümle).
2// Çalıştırma: java Ornek2.java
3public class Ornek2 {
4
5    public static void main(String[] args) {
6        int N = 50_000;
7
8        // KÖTÜ: döngüde "+=" -> her adımda YENİ String kopyalanır (O(n^2) toplam).
9        long t1 = System.currentTimeMillis();
10        String s = "";
11        for (int i = 0; i < N; i++) s += i;     // her seferinde yeni nesne!
12        long sure1 = System.currentTimeMillis() - t1;
13
14        // İYİ: StringBuilder -> aynı tampona ekler (O(n) toplam).
15        long t2 = System.currentTimeMillis();
16        StringBuilder sb = new StringBuilder();
17        for (int i = 0; i < N; i++) sb.append(i);
18        String sonuc = sb.toString();
19        long sure2 = System.currentTimeMillis() - t2;
20
21        System.out.printf("Döngüde birleştirme (%d):%n", N);
22        System.out.printf("  String += : ~%4d ms  (uzunluk %d)%n", sure1, s.length());
23        System.out.printf("  StringBuilder: ~%4d ms  (uzunluk %d)%n", sure2, sonuc.length());
24        System.out.println("  Kat fark ~ " + (sure2 == 0 ? ">>" : (sure1 / Math.max(1, sure2)) + "x"));
25
26        System.out.println("""
27
28                --- Neden döngüde StringBuilder? ---
29                String değişmez; "s += i" her turda eski içeriği + yeniyi YENİ bir String'e kopyalar.
30                N tur için bu O(n^2) iş demektir -> büyük N'de ciddi yavaşlık.
31                StringBuilder aynı genişleyen tampona ekler -> O(n). Döngüde metin kuruyorsan ŞART.
32                Not: TEK satırlık sabit birleştirmelerde (a + b + c) derleyici zaten StringBuilder kullanır;
33                orada elle StringBuilder gerekmez. Asıl fark DÖNGÜLERDEDİR.
34
35                StringBuffer: StringBuilder ile aynı API ama metotları senkronize (thread-safe).
36                Tek thread'de StringBuilder daha hızlıdır; StringBuffer'ı yalnızca paylaşılan
37                değiştirilebilir metin GERÇEKTEN gerektiğinde kullan (nadir).""");
38    }
39}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.