String, StringBuilder, Character ve düzenli ifadeler
String metotları ve değişmezlik, StringBuilder ile değiştirilebilir metin, Character sınıfı ve regex ile doğrulama, split, replaceAll. Kısa çıktı sorularıyla dolu bir konu.
Metin işleme her programda var: kullanıcı adı doğrulamak, CSV satırı bölmek, kelime saymak. Sınavda bu konu kısa ama tuzaklı çıktı soruları olarak gelir: substring’in bitiş indeksi, String’in değişmezliği, char aritmetiği, split’in boş parçaları. Bir de “write a method” sorusu: palindrom, kelime sayma, büyük harfe çevirme.
Altın kurallar:
- String değişmezdir (immutable). Metotlar yeni String döndürür; atamazsan sonuç kaybolur.
substring(a, b)b’yi almaz. Uzunlukb - a.- char bir sayıdır.
'A' + 2int verir (67); karakter istiyorsan cast et. - Değişen metin için StringBuilder. Metotları aynı nesneyi değiştirir.
- Regex’te ters bölü Java String’inde iki kez yazılır:
"\\d+".
String metotları
String s = "Object Oriented";
System.out.println(s.length());
System.out.println(s.charAt(7));
System.out.println(s.indexOf('e'));
System.out.println(s.lastIndexOf('e'));
System.out.println(s.indexOf("Or"));
System.out.println(s.indexOf('z'));
System.out.println(s.substring(7));
System.out.println(s.substring(0, 6));
System.out.println(s.substring(2, 4));
System.out.println(s.toUpperCase() + " " + s.toLowerCase());
System.out.println("[" + " hi there ".trim() + "]");
System.out.println(s.replace('e', '3'));
System.out.println(s.startsWith("Obj") + " " + s.endsWith("ED") + " " + s.contains("ted"));
15
O
3
13
7
-1
Oriented
Object
je
OBJECT ORIENTED object oriented
[hi there]
Obj3ct Ori3nt3d
true false true
indeks: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
karakter O b j e c t _ O r i e n t e d (_ = boşluk)
substring(2, 4) → 2 ve 3 → "je" substring(7) → 7'den sona → "Oriented"
| Metot | Döner | Not |
|---|---|---|
length() | int | Dizide length alan, String’de metot |
charAt(i) | char | i >= length() ise StringIndexOutOfBoundsException |
indexOf(x) / lastIndexOf(x) | int | Bulamazsa -1 |
substring(a, b) | String | a dahil, b hariç |
equals, equalsIgnoreCase | boolean | İçerik karşılaştırma |
compareTo | int | Sözlük sırası, ilk farklı karakterin kod farkı |
toUpperCase, toLowerCase, trim | String | Yeni String |
replace(a, b) | String | Düz metin değiştirme, hepsini |
split(regex) | String[] | Parçalara böler |
toCharArray() | char[] | Karakter dizisi |
String.valueOf(x) | String | Sayıyı metne çevirir |
TUZAK · sınırlar.
"java".substring(2, 5)ve"java".charAt(4)çalışırkenStringIndexOutOfBoundsExceptionfırlatır. Ama"java".substring(4)hata vermez, boş String döner (isEmpty()true).
Değişmezlik (immutability)
String nesnesi bir kez yaratılınca içeriği değişmez. toUpperCase, concat, replace gibi metotlar yeni bir String üretir.
String t = "java";
t.toUpperCase(); // sonuç atanmadı, kayboldu
t.concat("!"); // aynı
System.out.println(t);
t = t.toUpperCase(); // t artık yeni nesneyi gösteriyor
System.out.println(t);
java
JAVA
Aynı sebeple String u = "A"; String v = u; v += "B"; sonrasında u hâlâ "A": += yeni nesne yaratıp v’ye atar. StringBuilder’da ise iki referans aynı nesneyi değiştirir (aşağıda).
Karşılaştırma
System.out.println("Java".equals("java") + " " + "Java".equalsIgnoreCase("java"));
System.out.println("Apple".compareTo("apple"));
System.out.println("cat".compareTo("car"));
System.out.println("ab".compareTo("abcd"));
false true
-32
2
-2
Character sınıfı ve char aritmetiği
char aslında 16 bitlik bir sayıdır (Unicode kodu). Aritmetik işleme girince int’e yükselir. Ezberle: '0' = 48, 'A' = 65, 'a' = 97; büyük ve küçük harf arası 32.
System.out.println('A' + 2); // int
System.out.println((char) ('A' + 2)); // char
System.out.println("A" + 2); // String birleştirme
char c = 'x';
c++; // ++ char olarak kalır
System.out.println(c);
System.out.println('7' - '0'); // rakamın değeri
67
C
A2
y
7
Character sınıfının static metotları:
| Metot | Örnek | Sonuç |
|---|---|---|
isLetter(c) | isLetter('B') | true |
isDigit(c) | isDigit('7') | true |
isLetterOrDigit(c) | isLetterOrDigit('_') | false |
isUpperCase(c) / isLowerCase(c) | isUpperCase('b') | false |
isWhitespace(c) | isWhitespace(' ') | true |
toUpperCase(c) / toLowerCase(c) | toUpperCase('q') | 'Q' |
getNumericValue(c) | getNumericValue('8') | 8 |
String mix = "a1B2 c3!";
int letters = 0, digits = 0, upper = 0, spaces = 0;
for (int i = 0; i < mix.length(); i++) {
char ch = mix.charAt(i);
if (Character.isLetter(ch)) letters++;
if (Character.isDigit(ch)) digits++;
if (Character.isUpperCase(ch)) upper++;
if (Character.isWhitespace(ch)) spaces++;
}
System.out.println(letters + " " + digits + " " + upper + " " + spaces);
3 3 1 1
StringBuilder
Metni parça parça kuruyorsan ya da sık değiştiriyorsan StringBuilder kullan. İçeriği değiştirilebilir (mutable); metotları aynı nesneyi değiştirip onu geri döndürür, bu yüzden zincirleme yazılır.
StringBuilder sb = new StringBuilder("code");
sb.append(42).append('!');
System.out.println(sb);
sb.insert(0, "my ");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
sb.reverse().deleteCharAt(sb.length() - 1).setCharAt(0, 'M');
System.out.println(sb + " len=" + sb.length());
StringBuilder sb2 = new StringBuilder("abc");
sb2.replace(1, 2, "XYZ"); // 1 dahil, 2 hariç
System.out.println(sb2);
sb2.delete(0, 2);
System.out.println(sb2);
code42!
my code42!
!24edoc ym
My code42 len=9
aXYZc
YZc
| String | StringBuilder |
|---|---|
| Değişmez | Değişebilir |
s = s + x her seferinde yeni nesne | sb.append(x) aynı nesne |
equals içerik karşılaştırır | equals override edilmemiş: adres |
reverse yok | reverse() var |
Literal ile yaratılır: "abc" | new StringBuilder("abc") |
StringBuilder x = new StringBuilder("hi"), y = new StringBuilder("hi");
System.out.println(x.equals(y));
System.out.println(x.toString().equals(y.toString()));
StringBuilder p = new StringBuilder("A");
StringBuilder q = p;
q.append("B"); // aynı nesne
System.out.println(p);
false
true
AB
TUZAK · başa ekleyen döngü.
r = i + r;verb.insert(0, i);ikisi de her elemanı başa koyar. 0’dan 3’e döngüde ikisi de3210üretir. Sona ekleseydin0123olurdu.
Düzenli ifadeler (regular expressions)
Regex, bir metin kalıbını tarif eden küçük bir dildir. Java’da üç yerde kullanırsın: matches (doğrulama), split (bölme), replaceAll (değiştirme).
| Kalıp | Anlamı | Örnek uyan |
|---|---|---|
. | herhangi bir karakter | a, 7, ! |
\d / \D | rakam / rakam olmayan | 5 |
\w | harf, rakam ya da _ | x, _ |
\s | boşluk karakteri (space, tab, newline) | " " |
[abc] | a, b ya da c | b |
[a-z], [A-Z0-9] | aralık | k, Q, 4 |
[^0-9] | rakam olmayan | x |
X* | X sıfır ya da daha çok | "", XXX |
X+ | X bir ya da daha çok | X, XX |
X? | X olabilir de olmayabilir de | colou?r → color, colour |
X{n}, X{n,}, X{n,m} | tam n, en az n, n ile m arası | \d{9} |
Java String’inde \ kaçış karakteri olduğu için regex’in her ters bölüsü iki kez yazılır: regex’te \d+, Java’da "\\d+". Nokta gibi özel bir karakteri düz anlamında aramak için de kaçırırsın: "\\.".
matches: doğrulama
matches metnin tamamının kalıba uyup uymadığını söyler.
System.out.println("202312345".matches("\\d{9}")); // 9 haneli öğrenci no
System.out.println("20231234".matches("\\d{9}"));
System.out.println("abc123".matches("[a-z]+\\d+"));
System.out.println("abc123x".matches("[a-z]+\\d+"));
System.out.println("Ankara".matches("[A-Z][a-z]*")); // büyük harfle başlayan kelime
System.out.println("ali@bau.edu.tr".matches("[\\w.]+@[\\w.]+\\.[a-z]{2,}"));
System.out.println("05321234567".matches("05\\d{9}")); // cep telefonu
true
false
true
false
true
true
true
split ve replaceAll
System.out.println(Arrays.toString("a,b,,c,,".split(",")));
System.out.println("a,b,,c,,".split(",").length);
System.out.println(Arrays.toString(",x,y".split(",")));
System.out.println(Arrays.toString(" one two three ".trim().split("\\s+")));
System.out.println(Arrays.toString("1.5.9".split("\\.")));
System.out.println("1.5.9".split(".").length); // "." her karakter: hepsi ayırıcı
[a, b, , c]
4
[, x, y]
[one, two, three]
[1, 5, 9]
0
System.out.println("programming".replaceAll("[aeiou]", "*"));
System.out.println("a1b22c333".replaceAll("\\d+", "#"));
System.out.println("too many spaces".replaceAll(" +", " "));
System.out.println("2026-10-28".replaceAll("(\\d+)-(\\d+)-(\\d+)", "$3/$2/$1"));
System.out.println("x.y.z".replace(".", "-") + " " + "x.y.z".replaceAll(".", "-"));
pr*gr*mm*ng
a#b#c#
too many spaces
28/10/2026
x-y-z -----
Parantezler grup (group) oluşturur; değiştirme metninde grupları sırayla 1, 2, 3 numaralarıyla geri çağırabilirsin (yukarıdaki tarih örneği).
Pattern ve Matcher
Metnin içinde kalıba uyan bütün parçaları tek tek bulmak için:
Matcher m = Pattern.compile("\\d+").matcher("Room 12, floor 3, gate 104");
int sum = 0;
while (m.find()) {
System.out.print(m.group() + " ");
sum += Integer.parseInt(m.group());
}
System.out.println("sum=" + sum);
12 3 104 sum=119
matches bütün metni ister, find metnin içinde bir sonraki uyan parçayı arar.
Çözümlü yazma sorusu: palindrom
“A man, a plan, a canal: Panama” harf ve rakam dışındakiler atılıp küçük harfe çevrilince tersiyle aynı mı?
static boolean isPalindrome(String s) {
StringBuilder clean = new StringBuilder();
for (char c : s.toCharArray())
if (Character.isLetterOrDigit(c)) clean.append(Character.toLowerCase(c));
String fwd = clean.toString(); // reverse'ten ÖNCE kopyala
return fwd.equals(clean.reverse().toString());
}
System.out.println(isPalindrome("A man, a plan, a canal: Panama"));
System.out.println(isPalindrome("Java"));
true
false
fwd’yi reverse’ten önce almak şart: reverse aynı nesneyi çevirir. clean.toString().equals(clean.reverse().toString()) da çalışır (soldaki önce değerlendirilir), ama ayrı değişken okunaklı.
Sık yapılan hatalar
| Yanlış düşünce | Doğrusu |
|---|---|
s.toUpperCase(); s’yi değiştirir | Yeni String döner; s = s.toUpperCase(); |
substring(2, 4) 3 karakter | b hariç: 2 karakter |
s.length | String’de metot: s.length() |
'A' + 2 → C | 67; karakter için (char) ('A' + 2) |
sb1.equals(sb2) içerik karşılaştırır | StringBuilder’da adres; toString() ile karşılaştır |
split(".") noktadan böler | Regex’te nokta her karakter; split("\\.") |
| split sondaki boş parçaları tutar | Atar; baştakini tutar |
matches("\\d+") metinde rakam var mı? | Bütün metin rakam mı? İçinde aramak için Matcher.find |
s.charAt(0) = 'b'; | Derlenmez; String değişmez |
Döngüde s += x sorun değil | Her adımda yeni nesne; StringBuilder kullan |
Kendini test et
Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.
What is printed?
String s = "Object Oriented";
System.out.println(s.indexOf('e') + " " + s.lastIndexOf('e'));
System.out.println(s.substring(2, 4) + s.substring(7, 8));Cevabı göster
İndeksler 0'dan başlar: O0 b1 j2 e3 c4 t5 (boşluk)6 O7 r8 i9 e10 n11 t12 e13 d14. İlk 'e' 3'te, son 'e' 13'te. substring(2, 4) 2 ve 3'ü alır (bitiş hariç): "je". substring(7, 8) sadece 7: "O".
What is printed?
String t = "java";
t.toUpperCase();
t.concat("!");
System.out.println(t);Cevabı göster
String değişmezdir (immutable). toUpperCase ve concat yeni bir String döndürür, t'nin gösterdiği nesneyi değiştirmez. Dönen değer bir yere atanmadığı için kaybolur. Doğrusu t = t.toUpperCase();.
What is printed?
System.out.println('A' + 2);
System.out.println((char) ('A' + 2));
System.out.println("A" + 2);
System.out.println('7' - '0');Cevabı göster
char sayısal bir tiptir: 'A' + 2 int toplamıdır, 65 + 2 = 67. Sonucu char'a cast edersen 67 numaralı karakter: C. "A" String olduğu için + birleştirir: A2. Rakam karakterinden '0' çıkarmak rakamın değerini verir: 55 − 48 = 7.
What is printed?
StringBuilder sb = new StringBuilder("code");
sb.append(42).append('!');
sb.insert(0, "my ");
System.out.println(sb);
sb.reverse();
System.out.println(sb);Cevabı göster
StringBuilder değiştirilebilir; metotlar aynı nesneyi değiştirir ve onu döndürür (zincirleme yazılabilir). "code" → "code42" → "code42!" → başa "my " ekle: "my code42!". reverse karakterleri ters çevirir: "!24edoc ym".
What is printed?
StringBuilder x = new StringBuilder("hi"), y = new StringBuilder("hi");
System.out.println(x.equals(y));
System.out.println(x.toString().equals(y.toString()));Cevabı göster
StringBuilder equals'ı override etmez; Object'in equals'ı adres karşılaştırır, iki ayrı nesne: false. İçeriği karşılaştırmak için önce String'e çevir: true. (Java 11'den beri x.compareTo(y) == 0 da çalışır.)
What is printed?
System.out.println(Arrays.toString("a,b,,c,,".split(",")));
System.out.println(Arrays.toString(",x,y".split(",")));Cevabı göster
İki virgül arası boş String üretir: a, b, "", c. Sondaki boş parçalar split tarafından atılır, bu yüzden dizi 4 elemanlı. Baştaki boş parça atılmaz: ilk eleman "".
What is printed?
System.out.println("202312345".matches("\\d{9}"));
System.out.println("20231234".matches("\\d{9}"));
System.out.println("abc123x".matches("[a-z]+\\d+"));Cevabı göster
matches bütün String'in kalıba uymasını ister. \\d{9} tam 9 rakam: ilki 9 haneli, ikincisi 8 haneli. [a-z]+\\d+ harfler sonra rakamlar ile biter; sondaki x uymuyor. Java String'inde regex'in \d'si "\\d" diye iki ters bölüyle yazılır.
What is printed?
System.out.println("programming".replaceAll("[aeiou]", "*"));
System.out.println("a1b22c333".replaceAll("\\d+", "#"));
System.out.println("x.y.z".replace(".", "-") + " " + "x.y.z".replaceAll(".", "-"));Cevabı göster
[aeiou] herhangi bir sesli harf: o, a, i yıldız olur. \\d+ bir ya da daha çok ardışık rakam, her grup tek # olur. replace düz metin değiştirir, replaceAll ise regex alır: regex'te . her karakter demek, beş karakterin hepsi tire olur.
What is printed?
String mix = "a1B2 c3!";
int letters = 0, digits = 0, upper = 0;
for (int i = 0; i < mix.length(); i++) {
char ch = mix.charAt(i);
if (Character.isLetter(ch)) letters++;
if (Character.isDigit(ch)) digits++;
if (Character.isUpperCase(ch)) upper++;
}
System.out.println(letters + " " + digits + " " + upper);Cevabı göster
Harfler: a, B, c (3). Rakamlar: 1, 2, 3 (3). Büyük harf: B (1). Boşluk ve ! hiçbir sayaca girmez.
What is printed?
System.out.println("Apple".compareTo("apple"));
System.out.println("cat".compareTo("car"));
System.out.println("ab".compareTo("abcd"));Cevabı göster
İlk farklı karakterin kod farkı döner. 'A' (65) − 'a' (97) = −32: büyük harfler küçüklerden önce gelir. "cat"/"car": ilk fark t (116) − r (114) = 2. "ab" "abcd"'nin başıyla aynı; fark yoksa uzunluk farkı döner: 2 − 4 = −2.
Find the compile error(s).
String s = "cat";
s.charAt(0) = 'b';
StringBuilder sb = "hello";
char c = s.substring(0, 1);Cevabı göster
charAt bir değer döner, değişken değil: javac unexpected type; required: variable, found: value. String'in harfi değiştirilemez; s = "b" + s.substring(1); ya da StringBuilder'ın setCharAt'i kullanılır. StringBuilder'a literal atanamaz: new StringBuilder("hello"). substring her zaman String döner, char için s.charAt(0).
Write a method capitalizeWords(String text) that returns the words of text separated by single spaces, each with its first letter upper case and the rest lower case. capitalizeWords(" hello wORLD from java ") returns Hello World From Java.
Cevabı göster
Önce baştaki ve sondaki boşlukları at, sonra bir ya da daha çok boşluktan böl. Döngüde String birleştirmek yerine StringBuilder kullan:
public static String capitalizeWords(String text) {
String[] words = text.trim().split("\\s+");
StringBuilder sb = new StringBuilder();
for (String w : words) {
if (sb.length() > 0) sb.append(' ');
sb.append(Character.toUpperCase(w.charAt(0)));
sb.append(w.substring(1).toLowerCase());
}
return sb.toString();
}trim yapılmasaydı split başta boş bir String üretirdi ve w.charAt(0) StringIndexOutOfBoundsException fırlatırdı.Doğrulama: Tüm kod örnekleri ve cevaplar JDK 26 ile çalıştırıldı (java verify/SEN1002/W08.java, W08b.java); derleme hataları javac ile denendi (verify/SEN1002/err/E08a-c.java).