Bölüm 11: Dizgiler

Bilgisayar ve Programlamaya Giriş
StringİndisMetotlarKarşılaştırmaBiçimleme
Sercan KÜLCÜ · Giresun Üniversitesi

Giriş

Öğrenme Çıktıları

Temsil

String ve char ayrımını açıklamak.

İşleme

İndis ve temel metotları kullanmak.

Karşılaştırma

İçerik ve referans karşılaştırmasını ayırmak.

Çıktı

printf ile biçimli metin üretmek.

Temeller

String Nedir?

  • String, karakter dizisini temsil eden java.lang sınıfıdır (import gerekmez).
  • Dizgi sabitleri çift tırnakla ("Tarkan"), char tek tırnakla ('T') yazılır.
  • String ilkel tip değil, değiştirilemez bir nesnedir; değişken nesnenin referansını tutar.
YığınHeapad0T1a2r3k4a5nString nesnesi: karakter dizisic'T'char: değer doğrudan yığında

Temeller

String Oluşturma

String ad = "Tarkan";
String bos = "";
String kopya = new String(ad);
String yok = null;
  • Çoğunlukla new kullanmadan dizgi sabiti tercih edilir.
  • "" uzunluğu 0 olan gerçek bir nesnedir; null ise hiçbir nesneyi göstermez (yok.length() → NullPointerException).
YığınHeapDizgi havuzu (sabitler)Tarkan""uzunluk 0Tarkannew: ayrıadboskopyayoknull

Temeller

Değiştirilemezlik

  • String oluşturulduktan sonra içeriği değişmez.
  • Birleştirme ve dönüştürme işlemleri yeni String üretir; eski nesne olduğu gibi kalır.
  • Sonucu kullanmak için dönen değer bir değişkene atanmalıdır.
  • Hiçbir değişkenin göstermediği nesneyi çöp toplayıcı (garbage collector) temizler.
YığınHeapMerhabas

String s = "Merhaba";

YığınHeapMerhabadeğişmediMerhaba!yenis

s = s + "!"; → yeni nesne; ok ona taşındı, eski nesne aynı.

Temeller · Kodu adım adım çalıştır

Değiştirilemezlik: toUpperCase()

YığınHeapDizgi havuzu (sabitler)javadil

dil, havuzdaki "java" nesnesini gösterir.

YığınHeapDizgi havuzu (sabitler)javaJAVAkimse göstermiyordil

toUpperCase() yeni bir "JAVA" nesnesi üretir; ama sonuç hiçbir değişkene atanmadı → kaybolur. dil hâlâ eski nesnede.

YığınHeapDizgi havuzu (sabitler)javaJAVAçöpdil

Eski nesne değişmediği için java yazar.

YığınHeapDizgi havuzu (sabitler)javaJAVAyeni nesnedil

Bu kez dönen yeni nesne dil'e atanır: ok yeni nesneye taşınır. "java" nesnesi yine aynen durur.

YığınHeapDizgi havuzu (sabitler)javaJAVAdil

JAVA yazar. Değişen nesne değil, değişkenin gösterdiği yerdir.

String dil = "java";
dil.toUpperCase();
System.out.println(dil); // java
dil = dil.toUpperCase();
System.out.println(dil); // JAVA

İndis

İndisleme

0G1i2r3e4s5u6nss.length() = 7s.charAt(0) → 'G's.charAt(6) → 'n'7✗
  • İlk karakter 0, son karakter length() − 1 indisindedir; length() bir metottur (dizilerdeki length alanından farklı).
  • charAt(i) o konumdaki char değerini döndürür; charAt(7) → StringIndexOutOfBoundsException.

Metotlar · Kodu adım adım çalıştır

Temel Metotlar

0J1a2v3a4␣5P6r7o8g9r10a11m12l13a14m15a

16 karakterlik dizgi (boşluk da bir karakterdir: indis 4).

0J1a2v3a4␣5P6r7o8g9r10a11m12l13a14m15a

length() → 16; indisler 0 … 15.

0J1a2v3a4␣5P6r7o8g9r10a11m12l13a14m15a▲ konum

indexOf aranan metnin ilk karakterinin indisini verir → 5 (yoksa −1).

0J1a2v3a4␣5P6r7o8g9r10a11m12l13a14m15a

substring(5, 16): 5 dahil, 16 hariç → 11 karakter: "Programlama".

0J1a2v3a4␣5P6r7o8g9r10a11m12l13a14m15a

contains("Java") → true. Hiçbir metot s'yi değiştirmedi.

0J1a2v3a4␣5P6r7o8g9r10a11m12l13a14m15a

Sonuçlar birleştirilip yazdırılır.

String s = "Java Programlama";
int uzunluk = s.length();
int konum = s.indexOf("Programlama");
String alt = s.substring(5, 16);
boolean icerir = s.contains("Java");
System.out.println(alt + " " + konum);

Metotlar

Sık String Metotları

MetotSonuç
length()Karakter/kod birimi sayısı
charAt(i)i konumundaki char
substring(a,b)a dahil, b hariç alt dizgi
indexOf(x)İlk konum veya -1
toLowerCase()Küçük harfli yeni String
trim() / strip()Kenar boşlukları kaldırılmış yeni String
s0M1e2r3h4a5b6asubstring(1, 4) → "erh"indexOf('a') → 4length() → 7indexOf('z') → -1toLowerCase() → "merhaba"

Metotlar · Kodu adım adım çalıştır

split ve replace Adım Adım

0a1,2b3,4,5cmetin0a1b2""3cpvirgüllerden 4 parça

split(",") metni virgüllerde keser: "a", "b", "", "c". Ardışık iki virgülün arası boş dizgi olur ve dizide yer alır.

0a1b2""3cpp.length = 4

Arrays.toString(p) → [a, b, , c], p.length → 4. (Dizinin sonundaki boş parçalar atılır: "a,b,,".split(",") yalnızca 2 parça verir.)

0a1l2i34v5e6l7is

s = "ali veli": 8 karakter, 3. indis boşluk.

0a1l2i34v5e6l7is0a1L2i34v5e6L7itreplace('l','L'): yeni nesne

replace('l', 'L') her 'l' karakterini 'L' yapar (indis 1 ve 6) ve yeni bir String döndürür; s ise bu satırda değişmez.

0a1L2i34v5e6L7it

t yazdırılır: aLi veLi.

0a1l2i34v5e6l7is

s hâlâ ali veli: String değiştirilemezdir, sonuç ancak dönen değerde bulunur.

String[] p = "a,b,,c".split(",");
System.out.println(Arrays.toString(p) + " " + p.length); // [a, b, , c] 4
String s = "ali veli";
String t = s.replace('l', 'L');
System.out.println(t); // aLi veLi
System.out.println(s); // ali veli

Metotlar

replace, replaceAll, join, valueOf, format

ÇağrıSonuç
"banana".replace('a', 'o')bonono
"banana".replace("an", "AN")bANANa
"a1b22c333".replaceAll("[0-9]+", "#")a#b#c#
"a1b22c333".replaceFirst("[0-9]+", "#")a#b22c333
"Ada Can Ece".replaceAll(" +", " ")Ada Can Ece
String.join(", ", "Ada", "Can", "Ece")Ada, Can, Ece
String.valueOf(3.5) / String.valueOf(new char[]{'h','i'})3.5 / hi
String.format(Locale.US, "%.2f", 3.14159)3.14
String.format(Locale.US, "%5d|%-5d|%05d", 42, 42, 42) 42|42 |00042
String.format(Locale.US, "%,d", 1234567)1,234,567

replace düz metin, replaceAll düzenli ifade arar; hepsi yeni String döndürür. Yerel ayar verilmezse %.2f Türkçe ayarlı bilgisayarda 3,14 yazar.

Metotlar

Alt Dizgi Sınırları: s = "PROGRAM"

PROGRAM01234567s.substring(0, 3) → "PRO"

İndisler karakterlerin arasındaki çizgiler gibi düşünülebilir: 0 ile 3 arası "PRO". Uzunluk = 3 − 0.

PROGRAM01234567s.substring(3, 7) → "GRAM"

Bitiş length() = 7 olabilir: son karakter dahil edilir.

PROGRAM01234567s.substring(3) → "GRAM"

Tek parametreli sürüm: başlangıçtan sona kadar.

PROGRAM01234567s.substring(2, 2) → ""

Başlangıç = bitiş → boş dizgi "" (hata değil).

PROGRAM01234567✗ 9 yoks.substring(5, 9) → StringIndexOutOfBoundsException

Bitiş > length() ya da başlangıç > bitiş → çalışma zamanı hatası.

  • substring(a, b): a dahil, b hariç; sonuç uzunluğu b − a.
  • Geçerli aralık: 0 ≤ a ≤ b ≤ length().

Metotlar · Kodu adım adım çalıştır

Uygulama: E-postayı Parçalama

0a1l2i3@4g5r6u7.8e9d10ueposta

11 karakterlik e-posta adresi; kullanıcı adını ve alan adını ayıracağız.

0a1l2i3@4g5r6u7.8e9d10u▲ ateposta

indexOf('@') → 3: ayırıcının konumu.

0a1l2i3@4g5r6u7.8e9d10u▲ ateposta

substring(0, 3): 0 dahil, 3 (@) hariç → "ali".

0a1l2i3@4g5r6u7.8e9d10u▲ ateposta

substring(4): @'den sonraki karakterden sona kadar → "gru.edu".

0a1l2i3@4g5r6u7.8e9d10ueposta

charAt(0) bir char döndürür: 'a' (tek tırnak).

0a1l2i3@4g5r6u7.8e9d10ueposta

Parçalar birleştirilerek yazdırılır.

0a1l2i3@4g5r6u7.8e9d10ueposta

Character.toUpperCase char'ı büyük harfe çevirir → A. eposta hiç değişmedi.

String eposta = "ali@gru.edu";
int at = eposta.indexOf('@');
String kullanici = eposta.substring(0, at);
String alan = eposta.substring(at + 1);
char ilk = eposta.charAt(0);
System.out.println(kullanici + " / " + alan);
System.out.println(Character.toUpperCase(ilk));

Karşılaştırma · Kodu adım adım çalıştır

== ile equals Farkı

YığınHeapDizgi havuzu (sabitler)Giresuna

Sabit "Giresun" dizgi havuzuna konur; a onu gösterir.

YığınHeapDizgi havuzu (sabitler)GiresunGiresunnew ile ayrı nesneab

new String(...) içerik aynı olsa da heap'te ayrı bir nesne açar.

YığınHeapDizgi havuzu (sabitler)GiresunGiresunnew ile ayrı nesneabc

Aynı sabit tekrar yazıldı: havuzdaki mevcut nesne paylaşılır → c ile a aynı oku taşır.

YığınHeapDizgi havuzu (sabitler)GiresunGiresunnew ile ayrı nesneabc

a == b: iki ok farklı nesneye gidiyor → false (içeriğe bakılmaz).

YığınHeapDizgi havuzu (sabitler)GiresunGiresunnew ile ayrı nesneabc

a == c: iki ok aynı nesnede → true.

YığınHeapDizgi havuzu (sabitler)GiresunGiresunnew ile ayrı nesneabc

equals karakterleri tek tek karşılaştırır: G=G, i=i, … → true. İçerik için daima equals.

String a = "Giresun";
String b = new String("Giresun");
String c = "Giresun";
System.out.println(a == b);      // false
System.out.println(a == c);      // true
System.out.println(a.equals(b)); // true

Karşılaştırma

Karşılaştırma Metotları

MetotAmaçÖrnek
equalsİçerik eşitliği"abc".equals("abc") → true
equalsIgnoreCaseBüyük-küçük harfi yok sayan eşitlik"Java".equalsIgnoreCase("JAVA") → true
startsWithBelirli metinle başlama"Giresun".startsWith("Gir") → true
endsWithBelirli metinle bitme"Giresun".endsWith("sun") → true
compareToSözlüksel sıra: <0, 0, >0"elma".compareTo("armut") → pozitif

compareTo Unicode değerlerine göre çalışır: büyük harfler küçüklerden önce gelir ve Türkçe harfler (ç, ğ, ı, ö, ş, ü) alfabe sırasına uymayabilir.

GiresunstartsWith("Gir") → trueendsWith("sun") → trueequals("giresun") → falseequalsIgnoreCase("giresun") → true

Karşılaştırma · Kodu adım adım çalıştır

compareTo: Karakter ve Uzunluk Farkı

0e1l2m3ax

Önce x = "elma" (4 karakter). Karşılaştırma bu karakterlerin Unicode kodlarına göre yapılır.

0e1l2m3ax0a1r2m3u4ty

y = "armut" (5 karakter). Sıradaki satırda x.compareTo(y) hesaplanacak.

0e1l2m3ax0a1r2m3u4ty'e' (101) - 'a' (97) = 4

İlk farklı konum 0: 'e' - 'a' = 101 - 97 = 4. Pozitif: "elma" sözlükte "armut"tan sonra gelir.

0k1e2d3ik

k = "kedi" (4 karakter). Şimdi bir dizgi diğerinin başlangıcıysa ne olduğuna bakalım.

0k1e2d3ik0k1e2d3i4l5e6rargilk 4 karakter eşit: fark yok

k.compareTo("kediler"): ilk 4 karakter aynı ve "kedi" bitiyor; sonuç uzunluk farkıdır.

0k1e2d3ik0k1e2d3i4l5e6rarg4 - 7 = -3 (uzunluk farkı)

4 - 7 = -3: kısa olan "kedi" önce gelir. Kural: farklı karakter varsa karakter farkı, yoksa uzunluk farkı.

String x = "elma";
String y = "armut";
System.out.println(x.compareTo(y)); // 4
String k = "kedi";
System.out.println(k.compareTo("kediler")); // -3

Karşılaştırma

Türkçe Karakter ve Locale

Çağrı (tr = Locale.forLanguageTag("tr"))Sonuç
"TITLE".toLowerCase(Locale.ENGLISH)title
"TITLE".toLowerCase(Locale.forLanguageTag("tr"))tıtle
"i".toUpperCase(tr)İ
"i".toUpperCase(Locale.ENGLISH)I
"I".toLowerCase(tr)ı
"ISPARTA".toLowerCase(tr)ısparta
"ısparta".toUpperCase(tr)ISPARTA
  • Parametresiz toLowerCase() makinenin varsayılan diline bağlıdır: aynı kod başka bilgisayarda başka sonuç verebilir.
  • Anahtar sözcük, dosya uzantısı gibi teknik metinde Locale.ENGLISH, Türkçe metinde Locale.forLanguageTag("tr") verilir.
  • "TITLE".toLowerCase(tr).equals("title") → false; "title".equalsIgnoreCase("TITLE") → true.

Bellek

Dizgi Havuzu

  • Aynı dizgi sabitleri havuzdaki tek bir nesneyi paylaşır (bellek tasarrufu; değiştirilemezlik sayesinde güvenli).
  • new String(...) her zaman ayrı nesne oluşturur.
  • Bir String'in havuzdan mı geldiği koda bakınca her zaman anlaşılmaz; bu yüzden içerik karşılaştırmasında == değil equals kullanılır.
YığınHeapDizgi havuzu (sabitler)GiresunpaylaşılırGiresunnewacb

Bellek

Sabit Birleştirme ve intern

String a = "a", b = "b";
String r = a + b;
final String f = "a";
System.out.println(("a" + "b") == "ab");  // true
System.out.println((f + "b") == "ab");    // true
System.out.println(r == "ab");            // false
System.out.println(r.equals("ab"));       // true
System.out.println(r.intern() == "ab");   // true
Neden?

Sabit ifadeleri ("a" + "b", final değişken) derleyici birleştirir; sonuç havuzdaki "ab"'dir. a + b çalışma zamanında yeni nesne üretir; intern() havuzdaki nesneyi verir.

Null güvenli karşılaştırma

String x = null; iken "sabit".equals(x) → false, ama x.equals("sabit") → NullPointerException. Bu yüzden sabit değer sola yazılır.

Girdi

Scanner ile Metin Girdisi

import java.util.Scanner;
// ...
Scanner klavye = new Scanner(System.in);
String kelime = klavye.next();
klavye.nextLine();
String satir = klavye.nextLine();
  • next() bir kelime okur: baştaki boşlukları atlar, ilk boşlukta/satır sonunda durur.
  • nextLine() satır sonuna (⏎) kadar her şeyi okur ve ⏎'ı tüketir.
  • next() veya nextInt() sonrası tamponda kalan ⏎, bir nextLine() ile ayrıca tüketilmelidir.
Ada⏎Merhaba dünya⏎① next() → "Ada"③ nextLine() → "Merhaba dünya"② nextLine() → "" (yalnız ⏎ tüketilir)tampon: Ada⏎Merhaba dünya⏎⏎ = satır sonu (Enter)

Girdi · Kodu adım adım çalıştır

Kod İzleme: next() ve nextLine()

Klavye tamponu (System.in)▲ okuma konumu

Scanner klavye akışına bağlanır; tampon şimdilik boş.

Klavye tamponu (System.in)Ada⏎▲ okuma konumu

next() okuyacak bir şey bulamaz ve bekler. Kullanıcı Ada yazıp Enter'a basar → tampona "Ada⏎" girer.

Klavye tamponu (System.in)Ada⏎▲ okuma konumu

next() boşluk/satır sonuna kadar okur → "Ada". ⏎ tamponda kalır.

Klavye tamponu (System.in)Ada⏎▲ okuma konumu

nextLine() ⏎'a kadar okur → "" (boş) döner ve ⏎'ı tüketir. Artık tampon temiz.

Klavye tamponu (System.in)Ada⏎Giresun␣Merkez⏎▲ okuma konumu

Tampon boş → nextLine() bekler. Kullanıcı Giresun Merkez yazıp Enter'a basar.

Klavye tamponu (System.in)Ada⏎Giresun␣Merkez⏎okuma konumu ▲

Satırın tamamı (boşluk dahil) okunur → "Giresun Merkez"; ⏎ tüketilir ama sonuca eklenmez.

Klavye tamponu (System.in)Ada⏎Giresun␣Merkez⏎okuma konumu ▲

İki değer yazdırılır.

Scanner klavye = new Scanner(System.in);
String kelime = klavye.next();
klavye.nextLine();
String satir = klavye.nextLine();
System.out.println(kelime + " | " + satir);

3. satır olmasaydı 4. satırdaki nextLine() kalan ⏎'ı okuyup hemen boş satır döndürürdü.

Performans

Birleştirme ve StringBuilder

  • + az sayıda dizgi birleştirme için okunaklıdır.
  • Döngüde s = s + x her turda yeni String oluşturur ve eskiyi kopyalar.
  • StringBuilder değiştirilebilir bir tampondur: append aynı nesneye ekler.
  • toString() tamponun o anki içeriğinden son String'i üretir.
String + (döngüde)1␣çöp1␣2␣çöp1␣2␣3␣yeni nesneStringBuilder1␣2␣3␣tek nesne

Performans · Kodu adım adım çalıştır

Kod İzleme: StringBuilder ile Birleştirme

YığınHeap""StringBuilder (değişebilir)metin

Boş, değiştirilebilir bir tampon oluşturulur.

YığınHeap""StringBuilder (değişebilir)metin

1 <= 3 → true

YığınHeap1␣StringBuilder (değişebilir)metin

append(1) ve append(' ') aynı nesneye ekler (yeni String yok) → "1 ".

YığınHeap1␣StringBuilder (değişebilir)metin

i++ → 2 <= 3 → true

YığınHeap1␣2␣StringBuilder (değişebilir)metin

append(2) ve append(' ') aynı nesneye ekler (yeni String yok) → "1 2 ".

YığınHeap1␣2␣StringBuilder (değişebilir)metin

i++ → 3 <= 3 → true

YığınHeap1␣2␣3␣StringBuilder (değişebilir)metin

append(3) ve append(' ') aynı nesneye ekler (yeni String yok) → "1 2 3 ".

YığınHeap1␣2␣3␣StringBuilder (değişebilir)metin

i++ → 4 <= 3 → false: döngü biter.

YığınHeap1␣2␣3␣StringBuilder (değişebilir)1␣2␣3␣Stringmetinsonuc

toString() tampondan tek bir String üretir.

YığınHeap1␣2␣3␣StringBuilder (değişebilir)1␣2␣3␣Stringmetinsonuc

Sondaki boşluk görünsün diye | eklendi.

StringBuilder metin = new StringBuilder();
for (int i = 1; i <= 3; i++) {
    metin.append(i).append(' ');
}
String sonuc = metin.toString();
System.out.println(sonuc + "|");

Uygulamalar · Kodu adım adım çalıştır

Dizgiyi Ters Çevirme

0J1a2v3asters""

Dizgiyi sondan başa doğru okuyup yeni bir dizgiye ekleyeceğiz.

0J1a2v3asters""

Boş dizgiyle başlanır.

0J1a2v3a▲ isters"a"

i = 3: s.charAt(3) = 'a' eklenir → "a" (her += yeni String üretir).

0J1a2v3a▲ isters"av"

i = 2: s.charAt(2) = 'v' eklenir → "av" (her += yeni String üretir).

0J1a2v3a▲ isters"ava"

i = 1: s.charAt(1) = 'a' eklenir → "ava" (her += yeni String üretir).

0J1a2v3a▲ isters"avaJ"

i = 0: s.charAt(0) = 'J' eklenir → "avaJ" (her += yeni String üretir).

0J1a2v3asters"avaJ"

i = −1 → döngü biter; sonuç yazdırılır.

0J1a2v3ast2"avaJ"

Kısa yol: StringBuilder'ın hazır reverse() metodu aynı sonucu verir.

0J1a2v3ast2"avaJ"

İki yöntem de aynı çıktıyı üretir; s hiç değişmedi.

String s = "Java";
String ters = "";
for (int i = s.length() - 1; i >= 0; i--)
  ters += s.charAt(i);
System.out.println(ters);
String t2 = new StringBuilder(s).reverse()
                                .toString();
System.out.println(t2);

Uygulamalar · Kodu adım adım çalıştır

Palindrom: Harf Büyüklüğü ve Boşluk Yok Sayılarak

0E1y2␣3E4d5i6p7␣8A9d10a11n12a13d14a15␣16p17i18d19e20␣21y22ecumle

Cümle büyük harf ve boşluk içeriyor; doğrudan karşılaştırırsak 'E' ≠ 'e' olur.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18et

toLowerCase() ve replace(" ", "") → "eyedipadanadapideye" (19 karakter).

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

İki uç işaretçi: sol = 0, sag = 18. Aksi kanıtlanana kadar palindrom = true.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'e' ile 'e' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'y' ile 'y' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'e' ile 'e' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'd' ile 'd' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'i' ile 'i' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'p' ile 'p' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'a' ile 'a' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'd' ile 'd' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ sol▲ sagt

'a' ile 'a' → eşit, içe doğru ilerlenir.

0e1y2e3d4i5p6a7d8a9n10a11d12a13p14i15d16e17y18e▲ solsagt

sol = 9, sag = 9: işaretçiler buluştu, tüm çiftler eşit → true.

String cumle = "Ey Edip Adanada pide ye";
String t = cumle.toLowerCase().replace(" ", "");
int sol = 0, sag = t.length() - 1;
boolean palindrom = true;
while (sol < sag && palindrom) {
  if (t.charAt(sol) != t.charAt(sag))
    palindrom = false;
  sol++; sag--;
}
System.out.println(palindrom);

Uygulamalar · Kodu adım adım çalıştır

Sesli Harf Sayma

0m1e2r3h4a5b6a7␣8d9ü10n11y12assayac0

Önce hepsi küçük harfe çevrilir; sesliler dizgisi Türkçe sesli harfleri tutar.

0m1e2r3h4a5b6a7␣8d9ü10n11y12assayac0

'm': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓sayac1

'e': indexOf → 1 ≥ 0 → sesli, sayac = 1.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓sayac1

'r': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓sayac1

'h': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓sayac2

'a': indexOf → 0 ≥ 0 → sesli, sayac = 2.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓sayac2

'b': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓sayac3

'a': indexOf → 0 ≥ 0 → sesli, sayac = 3.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓sayac3

'␣': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓sayac3

'd': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓✓sayac4

'ü': indexOf → 7 ≥ 0 → sesli, sayac = 4.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓✓sayac4

'n': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓✓sayac4

'y': indexOf → -1 → sesli değil.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓✓✓sayac5

'a': indexOf → 0 ≥ 0 → sesli, sayac = 5.

0m1e2r3h4a5b6a7␣8d9ü10n11y12as✓✓✓✓✓sayac5

13 karakter tarandı: 5 sesli harf.

String s = "Merhaba Dünya".toLowerCase();
String sesliler = "aeıioöuü";
int sayac = 0;
for (int i = 0; i < s.length(); i++) {
  char c = s.charAt(i);
  if (sesliler.indexOf(c) >= 0) sayac++;
}
System.out.println(sayac);

Uygulamalar · Kodu adım adım çalıştır

Kelime Sayma (boşluk geçişleri)

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetinkelime0

Kelime = boşluk olmayan karakterlerin kesintisiz dizisi. Boşluktan harfe geçişleri sayacağız.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yenikelime1

'A' harf ve kelime dışındaydık → yeni kelime: kelime = 1.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yenikelime1

'l' aynı kelimenin devamı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yenikelime1

'i' aynı kelimenin devamı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yenikelime1

Boşluk → kelime dışına çıkıldı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yenikelime1

Yine boşluk (çift boşluk) → sayılmaz.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yenikelime2

'a' harf ve kelime dışındaydık → yeni kelime: kelime = 2.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yenikelime2

't' aynı kelimenin devamı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yenikelime2

'a' aynı kelimenin devamı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yenikelime2

Boşluk → kelime dışına çıkıldı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yeni▲ yenikelime3

'b' harf ve kelime dışındaydık → yeni kelime: kelime = 3.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yeni▲ yenikelime3

'a' aynı kelimenin devamı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yeni▲ yenikelime3

'k' aynı kelimenin devamı.

0A1l2i3␣4␣5a6t7a8␣9b10a11kmetin▲ yeni▲ yeni▲ yenikelime3

Sonuç 3. Kısa yol: metin.trim().split("\\s+").length (yalnızca boş olmayan metin için; boş metinde sonuç 0 değil 1 çıkar, önce isBlank() ile denetlenir).

String metin = "Ali  ata bak";
int kelime = 0;
boolean icinde = false;
for (int i = 0; i < metin.length(); i++) {
  char c = metin.charAt(i);
  if (c != ' ' && !icinde) {
    kelime++;
    icinde = true;
  } else if (c == ' ') icinde = false;
}
System.out.println(kelime);

Uygulamalar · Kodu adım adım çalıştır

Karakter Frekansı (int[26])

skavaka0b0c0d0e0f0g0h0i0j0k0l0m0n0o0p0q0r0s0t0u0v0w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

26 hücreli sayaç: 'a' → 0, 'b' → 1, … Harfin indisi c - 'a' ile bulunur (char'lar sayıdır).

skavaka0b0c0d0e0f0g0h0i0j0k1l0m0n0o0p0q0r0s0t0u0v0w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

'k' - 'a' = 107 − 97 = 10 → frekans[10] = 1.

skavaka1b0c0d0e0f0g0h0i0j0k1l0m0n0o0p0q0r0s0t0u0v0w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

'a' - 'a' = 97 − 97 = 0 → frekans[0] = 1.

skavaka1b0c0d0e0f0g0h0i0j0k1l0m0n0o0p0q0r0s0t0u0v1w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

'v' - 'a' = 118 − 97 = 21 → frekans[21] = 1.

skavaka2b0c0d0e0f0g0h0i0j0k1l0m0n0o0p0q0r0s0t0u0v1w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

'a' - 'a' = 97 − 97 = 0 → frekans[0] = 2.

skavaka2b0c0d0e0f0g0h0i0j0k2l0m0n0o0p0q0r0s0t0u0v1w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

'k' - 'a' = 107 − 97 = 10 → frekans[10] = 2.

skavaka2b0c0d0e0f0g0h0i0j0k2l0m0n0o0p0q0r0s0t0u0v1w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

k = 0: frekans > 0 → (char) ('a' + 0) = 'a' yazdırılır.

skavaka2b0c0d0e0f0g0h0i0j0k2l0m0n0o0p0q0r0s0t0u0v1w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

k = 10: frekans > 0 → (char) ('a' + 10) = 'k' yazdırılır.

skavaka2b0c0d0e0f0g0h0i0j0k2l0m0n0o0p0q0r0s0t0u0v1w0x0y0z0frekans[0] = 'a' … frekans[25] = 'z'

k = 21: frekans > 0 → (char) ('a' + 21) = 'v' yazdırılır. Tablo yalnızca a–z içindir; ç, ğ, ı, ö, ş, ü için ayrı bir düzen gerekir.

String s = "kavak";
int[] frekans = new int[26];
for (int i = 0; i < s.length(); i++) {
  char c = s.charAt(i);
  frekans[c - 'a']++;
}
for (int k = 0; k < 26; k++)
  if (frekans[k] > 0)
    System.out.println((char) ('a' + k)
                       + ": " + frekans[k]);

Uygulamalar · Kodu adım adım çalıştır

Sezar Şifreleme ve Çözme

metinsifreli0y1a2z3i4l5i6ma b c … x y zy + 3 → b (başa sarar)

Her harf alfabede 3 ileri kaydırılır. Sonuç StringBuilder'da biriktirilir.

metinsifreli0y1a2z3i4l5i6mb+3a b c … x y zy + 3 → b (başa sarar)

'y': (24 + 3) % 26 = 1 → 'b' (26'yı aştı, % 26 başa sardı).

metinsifreli0y1a2z3i4l5i6mbd+3a b c … x y zy + 3 → b (başa sarar)

'a': (0 + 3) % 26 = 3 → 'd'.

metinsifreli0y1a2z3i4l5i6mbdc+3a b c … x y zy + 3 → b (başa sarar)

'z': (25 + 3) % 26 = 2 → 'c' (26'yı aştı, % 26 başa sardı).

metinsifreli0y1a2z3i4l5i6mbdcl+3a b c … x y zy + 3 → b (başa sarar)

'i': (8 + 3) % 26 = 11 → 'l'.

metinsifreli0y1a2z3i4l5i6mbdclo+3a b c … x y zy + 3 → b (başa sarar)

'l': (11 + 3) % 26 = 14 → 'o'.

metinsifreli0y1a2z3i4l5i6mbdclol+3a b c … x y zy + 3 → b (başa sarar)

'i': (8 + 3) % 26 = 11 → 'l'.

metinsifreli0y1a2z3i4l5i6mbdclolp+3a b c … x y zy + 3 → b (başa sarar)

'm': (12 + 3) % 26 = 15 → 'p'.

metinsifreli0y1a2z3i4l5i6mbdclolpa b c … x y zy + 3 → b (başa sarar)

Şifreli metin bdclolp. Çözme: aynı döngüde kaydir yerine 26 - kaydir kullanılır → "yazilim".

String metin = "yazilim";
int kaydir = 3;
StringBuilder sifreli = new StringBuilder();
for (int i = 0; i < metin.length(); i++) {
  char c = metin.charAt(i);
  int yer = (c - 'a' + kaydir) % 26;
  char yeni = (char) ('a' + yer);
  sifreli.append(yeni);
}
System.out.println(sifreli);

Biçimleme

printf ile Biçimleme

String ad = "Java"; int adet = 3; double fiyat = 17.5;
System.out.printf("%-8s %3d %7.2f%n", ad, adet, fiyat);
%-8s␣%3d␣%7.2f%nbiçim dizgisiargümanlarad"Java"adet3fiyat17.5çıktı:Java␣␣␣␣sola yaslı, 8 genişlik␣␣␣3␣␣␣17.50

%-8s ← ad: "Java" 8 hücreye sola yaslanır, kalan 4 hücre boşluk.

%-8s␣%3d␣%7.2f%nbiçim dizgisiargümanlarad"Java"adet3fiyat17.5çıktı:Java␣␣␣␣␣␣␣3sağa yaslı, 3 genişlik␣␣␣17.50

%3d ← adet: 3 tam sayısı 3 hücreye sağa yaslanır.

%-8s␣%3d␣%7.2f%nbiçim dizgisiargümanlarad"Java"adet3fiyat17.5çıktı:Java␣␣␣␣␣␣␣3␣␣␣17.507 genişlik, 2 ondalık

%7.2f ← fiyat: 2 ondalıkla "17.50" (5 karakter) 7 hücreye sağa yaslanır.

%-8s␣%3d␣%7.2f%nbiçim dizgisiargümanlarad"Java"adet3fiyat17.5çıktı:Java␣␣␣␣␣␣␣3␣␣␣17.50⏎satır sonu

%n satır sonu ekler. Biçim belirteçleri argümanlarla sırayla eşleşir; tip uyuşmazsa hata oluşur.

%s metin, %d tam sayı, %f kayan noktalı sayı. Türkçe yerel ayarlı bilgisayarda %.2f ondalık ayırıcı olarak virgül basabilir (17,50).

Temeller

Unicode ve Metin

  • String, UTF-16 kod birimlerinden (char) oluşur; Türkçe harfler tek char'a sığar.
  • Bazı görünür karakterler (emoji, bazı simgeler) iki char ya da birden fazla Unicode kod noktası içerir.
  • Bu yüzden kullanıcıya görünen karakter sayısı için length() her durumda yeterli değildir.
"çay".length() = 3çaybir emoji (ör. gülen yüz): length() = 2← 1 görünen karakterD83DDE00← 2 char (UTF-16 çifti)

Özet

Bölüm Özeti

Değiştirilemezlik

String nesnesi değiştirilemez; toUpperCase, +, substring yeni nesne döndürür.

İndis

0 … length() − 1; substring(a, b): a dahil b hariç, uzunluk b − a.

Karşılaştırma

İçerik için equals, sıra için compareTo; == yalnızca referansı karşılaştırır.

Girdi / çıktı

next kelime, nextLine satır okur; yoğun birleştirmede StringBuilder, biçim için printf.

Özet

Kontrol Soruları

  1. String neden değiştirilemez olarak adlandırılır?
  2. substring başlangıç ve bitiş sınırlarını nasıl kullanır?
  3. == ile equals arasındaki fark nedir?
  4. next ve nextLine nasıl ayrılır?
  5. Döngü içinde neden StringBuilder tercih edilebilir?
Cevaplar
  1. Oluşturulduktan sonra karakterleri değiştirilemez; her “değişiklik” yeni bir nesne üretir.
  2. Başlangıç dahil, bitiş hariç; sonuç uzunluğu bitiş − başlangıç.
  3. == iki değişkenin aynı nesneyi gösterip göstermediğine, equals karakter içeriğine bakar.
  4. next boşlukta/satır sonunda durur ve ⏎'ı tamponda bırakır; nextLine satırın kalanını okur ve ⏎'ı tüketir.
  5. Her turda yeni String oluşturup kopyalamak yerine tek bir tampona ekler.

Özet

Alıştırmalar

  1. Bir cümledeki büyük harf, küçük harf, rakam ve boşluk sayılarını ayrı ayrı bulun.
  2. Bir kelimenin anagram olup olmadığını (ör. "elma" – "alem") karakter frekanslarıyla kontrol edin.
  3. Kullanıcının girdiği ad-soyadı "Soyad, Ad" biçiminde ve soyadı büyük harfle yazdırın.
  4. Bir cümledeki en uzun kelimeyi bulun (split ile).
  5. Sezar şifresini büyük harfleri de (A–Z) destekleyecek şekilde genişletin; diğer karakterler aynen kalsın.
  6. replace kullanmadan bir dizgideki tüm boşlukları silen kodu StringBuilder ile yazın.

Özet

Kaynaklar

  • Deitel ve Deitel, Java: How to Program, Early Objects, 11. baskı, Pearson, 2018.
  • Liang, Introduction to Java Programming and Data Structures, 13. baskı, Pearson, 2024.
  • Oracle, The Java Tutorials: Strings, The StringBuilder Class.
  • Oracle, Java SE 21 API: String, StringBuilder.
  • Sedgewick ve Wayne, Computer Science: An Interdisciplinary Approach, Addison-Wesley, 2016: 3.1 Using Data Types.
  • Unicode Consortium, The Unicode Standard.

Son

Dizgiler
Sonraki sunum: Özyineleme · Çalışma soruları · Simülatör: Dizgi Laboratuvarı · Terim sözlüğü
1 / 1Sercan KÜLCÜ, Tüm hakları saklıdır.