Arkadaşlar merhaba,

Bu yazımızda Java'da String sınıfına göz atacağız.

String

String sınıfı java'da en temel sınıflardan biridir.String sınıfı olmadan bir main() methodu bile yazamayız.

  • String Immutable(değişmez) bir nesnedir.

  • String final bir sınıftır dolayısıyla miras alınamaz.

    String sınıfının nesneleri iki şekilde oluşturulabilir.

new kurucu çağrısı ile ve kurucu çağrısı yapmadan, iki tane ikili kesme “ ” işareti ile oluşturulabilir.

Her new String kurucu çağrısı yeni bir String nesnesi oluşturur.

Her “ ” çağrısı yeni bir String nesnesi oluşturmaz eğer daha önce oluşturulmuş ise String havuzundaki nesneye bir referans döndürür.Yoksa yeni bir String nesnesi oluşturulur ve havuza konur.

Dolayısıyla String oluşturmak için new ile kurucu çağrısı yapmak yerine “ ” kullanmak avantajlıdır çünkü bu daha az nesne oluşturmak anlamına gelir.

Garbage collection’a daha az iş çıkaracağı için JVM'in performansı açısından olumludur.

String neseneleri değişmez olduklarından String nesnesini değiştirmek için yapılacak her şey yeni bir String nesnesi oluşturur. “+” operatörü de daima yeni bir String nesnesi döndürür.

String API’sindeki concat() gibi String nesnesini değiştiren metotlar da daima yeni bir String nesnesi döndürürler.

String nesnelerini oluşturmak ve değiştirmek için;

StringBuilder ve StringBuffer sınıfları kullanılır.

StringBuilder kendi durumunu değiştirir ve kendisine bir referans döndürür.

Aralarındaki fark StringBuilder thread senkronizasyonu sağlamazken StringBuffer sağlar dolayısıyla thread-safe’tir.

Dolayısıyla çok kanallı (multi-threaded) bir ortam söz konusu değilse StringBuilder kullanılması gereklidir.

String Birleştirme

Sayısal rakamlar + operatörü ile toplanırken String değerle ise birleştirilecektir.

System.out.println(1 + 2);   // 3
System.out.println("a" + "b");  // ab
System.out.println("a" + "b" + 3);  // ab3
System.out.println(1 + 2 + "c");  // 3c
System.out.println("c" + 1 + 2); // c12

Aşağıdaki örnekte 3 bir int değer olduğu için 3 ile 3'ü toplayacaktır. 5 ise String bir değerdir ve birleştirecektir.

int three = 3;
String five = "5";
System.out.println(1 + 2 + three + five);

// 65

İki sayı var ise toplama aksi taktirde birleştirme işlemi yapılacağını söylemiştik.

String s = "1";
s += "2";
s+= 3;

System.out.println(s); // 123

String Sınıfı Methodları

length()

Değerin uzunluk bilgisini yazdırır.

String string = "hayvanlar";
System.out.println("Uzunluk : " + string.length()); //  7

charAt()

charAt() methodu, belirli bir index'deki hangi karakterin olduğunu bulmamıza olanak tanır.

System.out.println(string.charAt(4));

System.out.println("charAt2 : " + string.charAt(3));

System.out.println(string.charAt(7));  // Hata

String bir karakter dizisi olduğu için string methodlarında index 0'dan başlar.

charAt methodundaki örnek gibi var olmayan bir index'i çağırdığımızda bir hata ile karşılaşırız.

indexOf()

indexOf() methodu, stringdeki karakterlere bakar ve istenen değerle eşleşen ilk index'i bulur.

indexOf, girdi olarak tek bir karakterle veya bir String'in tamamıyla çalışabilir. Ayrıca istenen bir pozisyondan başlayabilir.

charAt()'tan farklı olarak, indexOf() methodu bir eşleşme bulamazsa bir istisna oluşturmaz. indexOf(), eşleşme bulunmadığında –1 değerini döndürür.

System.out.println(string.indexOf('h'));   // 0

// 0'ncı index'den başla h harfini  ara.
System.out.println(string.indexOf("h", 0));   // 0

// index 3'den başla an karakterlerini ara.
System.out.println(string.indexOf("an", 3));   // 4

substring()

substring methodu string ifadeyi parçalara ayarmak için kullanılır.Method imzaları aşağıdaki gibidir.

String substring(int beginIndex) String substring(int beginIndex, int endIndex)

System.out.println("substring : " + string.substring(3)); // index 3'den başla sona kadar yazdır.
// vanlar

// eğer index'i bilmiyorsak
System.out.println(string.substring(string.indexOf('v')));
// vanlar

// tek karakter String yazdırır. index 4'ü dahil etmez.
System.out.println(string.substring(3, 4)); // 3 ile 4'ncü index arasındakileri yazdır.
// v

// index 3'den başla index 7'ye kadar yazdır.
System.out.println(string.substring(3, 7));
// vanl

Peki başlangıç ve bitiş değerleri olarak aynı index'i verirsek ?

 System.out.println("substring: 3-3 empty string " + string1.substring(3, 3)); // empty string
// bu şekilde boş bir string yazdıracaktır.

toLowerCase() ve toUpperCase()

String değeleri büyük ve küçük yazdırmak için kullanılır.

System.out.println(string1.toUpperCase());// HAYVANLAR
System.out.println("ABC123".toLowerCase()); // abc123

equals() ve equalsIgnoreCase()

equals() methodu, iki String nesnesinin aynı sırada tam olarak aynı karakterleri içerip içermediğini kontrol eder.

equalsIgnoreCase() methodu, gerektiğinde karakterlerin büyük/küçük harflerini dönüştürmesi dışında, iki String nesnesinin aynı karakterleri içerip içermediğini kontrol eder. Method imzaları aşağıdaki gibidir.

boolean equals(Object obj)

boolean equalsIgnoreCase(String str)
System.out.println("abc".equals("ABc"));   // false
System.out.println("ABC".equals("ABC"));   // true
System.out.println("abc".equalsIgnoreCase("ABc"));   // true

startsWith() - endsWith()

startWith() ve endWith() methodları, sağlanan değerin String'in bir kısmıyla eşleşip eşleşmediğine bakar. Method imzaları aşağıdaki gibidir:

boolean startsWith(String prefix) boolean endsWith(String suffix)

System.out.println("abc".startsWith("a"));   // true
System.out.println("abc".startsWith("A"));   // false
System.out.println("abc".endsWith("c"));    // true
System.out.println("abc".endsWith("a"));   // false

replace()

replace() methodu,string'de basit bir arama yapar ve değiştirir.

System.out.println("abcabc".replace('a', 'A'));   // AbcAbc
System.out.println("umutumut".replace("u", "U"));   // UmUtUmUt
System.out.println("abcabc".replace("a", "A"));   // AbcAbc

contains()

contains() yöntemi, String'deki eşleşmeleri arar. startWith() ve endWith() kadar net arama yapmaz.Eşleşme String'in herhangi bir yerinde olabilir.

System.out.println("abc".contains("b"));   // true
System.out.println("abc".contains("B"));   // false

trim(), strip(), stripLeading(), ve stripTrailing()

Method imzaları şu şekildedir:

  • String strip()
  • String stripLeading()
  • String stripTrailing()
  • String trim()

strip() ve trim() methodları, String'in başındaki ve sonundaki boşlukları kaldırır.

\t => ile tab

\n => yeni satır.

System.out.println("abc".strip()); 
System.out.println("\t a b c\n".strip());

System.out.println("Trim.length : " + text.trim().length());
System.out.println("strip.length :" + text.strip().length());
trim:abc
a b c
Trim.length : 3
strip.length :3

Java 11'e stripLeading() ve stripTrailing() methodları eklendi.

stripLeading() methodu, String'in başlangıcındaki boşlukları kaldırır ve sonunda bırakır.

stripTrailing() methodu bunun tersini yapar.String'in sonundaki boşlukları kaldırır ve başında bırakır.

String text = "  abc\t     ";
String text1 = " abc";

System.out.println("stripLeading: " + text.stripLeading());
System.out.println("stripTrailing: " + text.stripTrailing());

// stripLeading:abc     

// stripTrailing:    abc


System.out.println("stripLeading.length :" + text1.stripLeading().length());
//stripLeading.length :3 baştaki boşluğu kaldırdı ve uzunluğu yazdırdı.


System.out.println("stripTrailing.length :" + text1.stripTrailing().length()); 
//stripTrailing.length :4 sondaki boşluğu kaldırdı ve uzunluğu yazdırdı.

intern()

intern() methodu, varsa, string havuzundaki(pool) değeri döndürür. Aksi takdirde, değeri string havuzuna ekler.Method imzası aşağıdaki gibidir:

String intern()

System.out.println("intern : " + text.intern()) 
System.out.println("intern.length : " + text.intern());

// intern :   abc         
// intern.length :   abc

String Builder

String sınıfından farklı olarak StringBuilder değişmez değildir.

Aşağıdaki örneklerde gösterilidiği gibi StringBuilder nesneleri oluşturulabilir.

Son örnekte görüldüğü gibi değerin ne kadar büyük olacağını ve StringBuilder'in karakterler için bir kapasite ayırmasını istediğimizi söyleyebiliriz.

StringBuilder sb1 = new StringBuilder();
StringBuilder sb2 = new StringBuilder("selam");
StringBuilder sb3 = new StringBuilder(10);

Aşağıdaki örnekte yeni bir StringBuilder nesnesi oluşturulur. append(); methodu ile for döngüsü boyunca her seferinde StringBuilder nesnesine alfabenin sonuna yeni bir karakter ekler.

Bu kod her seferinde bir String oluşturmadan aynı StringBuilder'ı yeniden kullanır.

StringBuilder alfabe = new StringBuilder();
        for (char current = 'a'; current <= 'z'; current++)
            alfabe.append(current);
System.out.println("Alfabe : " + alfabe);

StringBuilder kendi durumunu değiştirir ve kendisine bir referans döndürür.

StringBuilder stringBuilder  = new StringBuilder("başlangıç");
stringBuilder.append("+orta");

StringBuilder same = stringBuilder.append("+son");

System.out.println("Aynı Nesne : " + stringBuilder);

// başlangıç + orta +son
StringBuilder a = new StringBuilder("abc");
StringBuilder b = a.append("de");
b = b.append("f").append("g");

System.out.println("a=" + a); 
System.out.println("b=" + b); 

// a=abcdefg
// b=abcdefg

StringBuilder Methodları

StringBuilder sb = new StringBuilder("animals");
String sub = sb.substring(sb.indexOf("a") , sb.indeOf("al")); // iki değer arasını yazdır.

int len = sb.length();
char ch = sb.charAt(6);

System.out.println("substring : " + sub + " " + len + " " + ch);

// substring : anim 7 s
StringBuilder sb2example = new StringBuilder("Umut Çakmak");
String sub2 = sb2example.substring(1,5); // 1-5 arasını yazdır.

int len1 = sb2example.length(); 
char ch1 = sb2example.charAt(5); // 5'nci karakteri al

System.out.println("sb2 Example : " + sb2example + " " + len1 + " " + "" + sub2 + "" + ch1);

// sb2 Example : Umut Çakmak 11 mut Ç

append()

Parametreyi StringBuilder'a ekler ve mevcut StringBuilder'a bir referans döndürür.

StringBuilder sb1 = new StringBuilder().append(1).append('c');
sb1.append("-").append(true);
System.out.println(sb1); 

// 1c-true

insert()

insert() yöntemi, istenen index'de StringBuilder'a karakterler ekler ve mevcut StringBuilder'a bir referans döndürür.

StringBuilder insert = new StringBuilder("UmutÇakmak");
insert.insert(4 , "-");
System.out.println(insert);

// Umut-Çakmak

delete() ve deleteCharAt()

delete() methodu, insert() methodunun tersidir. String'den karakterleri kaldırır ve geçerli string'e bir referans verir.

deleteCharAt() :sadece bir karakter simek içindir.

StringBuilder del = new StringBuilder("Umut Çakmak");
del.deleteCharAt(1);
del.delete(4,5);

System.out.println(del);

// Uut akmak

delete() methodu, string indexleri söz konusu olduğunda diğerlerinden daha esnektir. StringBuilder'ın sonunu aşan ikinci bir parametre belirtirseniz, Java yalnızca sonunu kastettiğinizi varsayar.

StringBuilder sb4 = new StringBuilder("abcdef");
sb4.delete(1, 100); 
System.out.println("Delete : " + sb4);

// Delete : a

replace()

replace() yöntemi, StringBuilder için String için olduğundan farklı şekilde çalışır.

Method imzası şu şekildedir.

StringBuilder replace(int startIndex, int endIndex, String newString)
StringBuilder builder = new StringBuilder("pigeon dirty");
builder.replace(3, 6, "sty");
System.out.println(builder);

// pigsty dirty
StringBuilder rep = new StringBuilder("GalataSa");
rep.replace(8 , 10,"ray");
System.out.println(rep);

// GalataSaray

delete metodu gibi 2.parametre boyutu aştığı için ilk parametreden sonrasını komple siler.

StringBuilder builder1 = new StringBuilder("dog dirty");
builder1.replace(3, 100, "");
System.out.println(builder1); 

// dog

reverse()

String'deki karakterleri tersine çevirir ve geçerli StringBuilder'a bir referans döndürür.

StringBuilder rev = new StringBuilder("Umut Çakmak");
rev.reverse();
System.out.println(rev);

// kamkaÇ tumU

toString()

Bir StringBuilder'ı bir String'e dönüştürür.

StringBuilder toSt = new StringBuilder("Umut Çakmak");
String s1 = toSt.toString();
System.out.println(s1);

// Umut Çakmak

equals() ve == Kullanımı

StringBuilder one = new StringBuilder();
StringBuilder two = new StringBuilder();
StringBuilder three = one.append("a");

System.out.println(one == two);   // false => Aynı nesne olmadığı için
System.out.println(one == three); // true

Bir ve iki tamamen ayrı StringBuilder nesneleridir ve bize iki nesne verir. Bu nedenle, ilk print ifadesi bize false verir.

Bu, bir ve üçün her ikisinin de aynı nesneyi gösterdiği anlamına gelir ve ikinci print ifadesi bize true verir.

String x = "Hello World";
String z = " Hello World".trim();
System.out.println(x.equals(z)); // true

İki StringBuilder referansında equals() methodunu çağırırsanız, referans eşitliğini kontrol eder. Bunun yerine eşitliği kontrol etmek için bir String almak için StringBuilder'da toString() methodunu kullanabilirsiniz.

String string = "a";
StringBuilder builder = new StringBuilder("a");

System.out.println(string == builder); // DOES NOT COMPILE

System.out.println("equals() : " + string.equals(builder));

// equals() : false

Lion örneğinde Lion sınıfı equals ve hashCode methodlarını override ederek karşılaştırma yapmadığı için false olarak yazdıracaktır.

Lion  l1 = new Lion();
Lion l2 = new Lion();
Lion l3 = l1;

System.out.println(l1 == l3); // true => aynı objenin referansları olduğu için true.
System.out.println(l1 == l2); // false => 2 obje referansları farklı olduğu için false

System.out.println(l1.equals(l2)); // false => farklı nesne

String Pool

Stringler Java'da bir çok yerde kullanıldığından çok fazla bellek kullanırlar. Java programda bir çok string'in tekrar ettiğini farkeder ve bu sorunu ortak alanları yeniden kullanarak çözer.

intern pool olarak bilinen bir string havuzu tüm stringleri toplayan JVM'de bir konumdur.

String pool programda değişmez değerleri ve sabiteleri(constant) içerir.

Örneğin, "name" bir hazır bilgidir (literal) ve bu nedenle string havuzuna gider. myObject.toString() bir string'dir, ancak hazır bilgi (literal) değildir bu nedenle string havuzuna girmez.

JVM, bellekte yalnızca bir sabit değer oluşturdu. x ve y bellekte aynı yeri gösterir; bu nedenle, ifade true yazdırır.

String x = "Selam";
String y = "Selam";

System.out.println(x == y); // true

Bu örnekte, aynı String literal'dan iki tane yok. x ve z aynı string'i değerlendirse de, biri çalışma zamanında hesaplanır. Derleme zamanında aynı olmadığı için yeni bir String nesnesi oluşturulur.

String x = "Hello World";
String z = " Hello World".trim();

System.out.println(x == z); // false

Birleştirme (concat), tıpkı bir methodu çağırmak gibidir ve yeni bir String ile sonuçlanır.

String singleString = "hello world";
String concat = "hello ";
concat += "world";

System.out.println(singleString == concat); // false

İlki, string havuzunu normal şekilde kullanır ikincisi ise yeni bir nesne oluşturur.

String x2 = "Hello World";
String y2 = new String("Hello World");

System.out.println(x2 == y2); // false

Ayrıca tersini yapabilir ve Java'ya string havuzunu kullanmasını söyleyebilirsiniz. intern() methodu, varsa, string havuzunda bir nesne kullanır. Eğer hazır bilgi henüz string havuzunda (string pool) değilse, Java bu sefer onu ekleyecektir.

Her iki değişken de string havuzunda aynı referansa işaret ettiğinden, == operatörünü kullanabiliriz.

String name = "Hello World";
String name2 = new String("Hello World").intern();
System.out.println(name == name2);

// true

first ve second compile time sabitesi olduğu için first ve second aynı string pool referansını paylaşır ve 1 ve 2'nci yazdırılan satır true'dur.

third constructor çağırılarak oluşturulduğu için compile time constant'ı değildir. 3'ncü yazdırılan değer false'dur.

Son satır intern() ile string pool üzerinden çağırıldığı için true'dur.

String first = "cat" + 
String second = "c" + "a" + "t" + "
String third = "c" + "a" + "t" + new String("

System.out.println(first == second); //  true
System.out.println(first == second.intern());  // true
System.out.println(first == third); // false
System.out.println(first == third.intern()); // true

Umarım faydalı olmuştur.