Değişkenlerin bellek(RAM) üzerinde nasıl saklandığına bir göz atalım.
RAM üzerinde STACK
ve HEAP
olarak adlandırılan iki bölüm bulunur.
-
STACK
bölümünde primitive ifadelerin değerleri bu bölümde tutulur. Primitive değişkenlerin hızlı olmasının sebeplerinden birisi bellekte bu bölümde tutulmalarıdır. ÇünküSTACK
,HEAP
'den daha hızlı çalışır. -
HEAP
bölümünde ise reference değerli olan tiplerin (class) değerleri ve nesneleriHEAP
bölümünde, bu değerlerin adreslerini gösteren değişkenler iseSTACK
bölümünde tutulur.
-
is
ve!is
OperatörleriÇalışma zamanında (runtime) bir nesnenin belirli bir türe uygun olup olmadığı işleminin kontrol edilmesi işlemidir.
val value: Any = "Merhaba, Kotlin!" if (value is String) { println(value.length) } if (value !is Int) { println("Değişken bir Int türünde değildir.") }
Örneğin bu örnekte
Any
tipine sahip bir değişkenimiz var. İlk olarak,is
anahtar kelimesiyle, değişkeninString
türünde olup olmadığını kontrol ediyoruz. Eğer öyleyse, ilgili mesajı yazdırıyoruz. Ardından,!is
kullanarak, değişkeninInt
türünde olmadığını kontrol ediyoruz. -
Peki
Smart Cast
Nedir?Kotlin dilinde bir değişkenin tipi üzerinde
compiler
tarafından otomatik olarak dönüşümün gerçekleştirilme işlemidir. Bu şekilde açık bir şekildeType Conversion
işlemini yapmadan o tipin sahip olduğu bütün özellikleri methodları kullanmamızı sağlar.Yine yukarıdaki örnekten devam edelim,
value
değişkenininString
olup olmadığını kontrol ettik veif
içerisinde açık bir şekildeType Conversion
işlemini yapmadanString
tipine ait olanlength
özelliğini kullanabildim. İşte tam olarak bu durumaSmart Cast(Akıllı Dönüşüm)
denir.val totalIntMax = Int.MAX_VALUE + Int.MAX_VALUE println(totalIntMax) // Sonuç: -2
Burada INT değerlerinin max değerleri ile bir toplama işlemi gerçekleştiriyorum ve
totalIntMax
değişkenimLong
bir değer olması gerekirkenInt
bir değer olarak belirleniyor.Ama biz bir önceki hafta eğer değer
Int
değer aralığının üzerinde iseType Inference
ile bu değişkeninLong
olarak atanacağını öğrenmiştik. Evet bu bilgi doğru ama IDE aritmetik işlemler de bu şekilde bir belirleme yapmıyor.Önce olası durumlara bir bakalım:
val intValuePlusLong = 34 + 43L // Long Toplama işleminde hangi tipin aralık değeri fazla ise o değerin tipi belirlenir. val byteMaxPlusByteMax = Byte.MAX_VALUE + Byte.MAX_VALUE // Int val shortMaxPlusShortMax = Short.MAX_VALUE + Short.MAX_VALUE // Int
Short
veByte
değerlerlerini topladığımızda ise tipInt
olarak belirlenir. Burada yine dilin bu değerler için sağlamış olduğu özel optimizasyonlar sebebi ileInt
olarak atanır.Burada IDE her bir toplama işlemi yapıldığında hangi değer aralığına geleceğini kontrol etmiyor. Bunu yapamaz mı? İsterse tabiki yapar sadece bir if kontrolü gerekiyor. Ama biz her toplama işlemi yaptığımızda arka planda bu işlem kontrolü sağlanacak ve bu da ek bir maliyet getirecektir. Buradan
Defansif Programlama
kavramına bir geçiş yapalım.-
Yazılımcıların yazdıkları kodda olası tüm durumları (edge case) ele alması durumudur. Burada gerçekten bütün edge case durumlarını değerlendirmelimiyiz? Bu en uç noktadaki edge case durumunu değerlendirmek bize bir performans kaybı yaratır mı? Eğer yaratacaksa bunu gerçekten kullanmalımıyız?
Yukarıdaki örnek gibi eğer her toplama işleminde bu değerlerin
Int
max değerini geçtiğini kontrol yapılsa idi gereksiz bir maliyet oluşturacaktı.
-
-
- 2 byte(16bits) alan yer kaplar.
- Tek tırnakların '' arasına harf, sayi, escape karakterlerini veya unicode yazarak kullanırız.
- Çift tırnak "" kullanırsak
String
olur.
val firstCharOfName = 'T' val firstCharOfName2 = "T" // String val firstCharOfName3 = 'TO'
Yukarıdaki
firstCharOfName3
gibi tek tırnaklar içerisine birden fazla character ekleyemeyiz. -
- ASCII tablosu, ASCII karakterlerini ve karşılık gelen sayısal değerleri içeren bir tablodur.
- ASCII tablosu, temel Latin alfabesi karakterlerini, rakamları, noktalama işaretlerini ve diğer özel karakterleri içerir.
Eğer bir karakter ifadeyi
toInt()
veyacode
ileInt
bir değere döndürmeye çalıştığımızda bize geri dönecek olan değer tabloda bu karaktere denk gelendecimal
karşılığını verecektir.println('H'.code) // 72 println('P'.code) // 80 println('7'.code) // 55
-
Burada
toInt()
de kullanabilirdik ama bu fonksiyonDeprecated
bir duruma geçmiş bunun yerinecode
property kullanmamız isteniyor. -
Eğer karakter içerisindeki sayısal değer ile işlem yapmak istiyorum bunun ASCII tablosundaki decimal karşılığını istemiyorum diyorsak,
digitToInt()
fonksiyonunu kullanabiliriz.
println('7'.digitToInt()) // 7 - Bu sefer decimal karşılığını vermedi.
- Burada dikkat etmemiz gereken bir durum var. Eğer char içerisinde Int'e dönüşü yapılamayacak bir değer var ise
program
IllegalArgumentException
hatasını verecektir.
println('T'.digitToInt())
-
\t
: Tab kadar bir boşluk bırakır.\b
:\n
: Yeni bir satıra geçmemizi sağlar.\r
: Satır başına dönmek için kullanılır.\'
: Tek tırnak karakterini kullanmak için. Örneğin bir String ifade içerisinde"Bu bir tek tırnak içeren bir string\'dir."
Bunu print ile çıktısını almaya çalıştığımızda sonuçBu bir tek tırnak içeren bir string'dir.
\"
: Çift tırnak karakterini kullanmak için\$
: Dollar ($) işaretini kullanmak için
-
Unicode, bilgisayar sistemlerinde metin ve sembollerin temsil edilmesi için kullanılan bir karakter kodlama standardıdır. Farklı dil ve alfabeleri destekler. (Örneğin Çince veya Japonca alfabelerini) - UTF-8, UTF-16, ve UTF-32 gibi çeşitleri vardır. Bu çeşitler arasındaki fark, destekledikleri toplam sembol, karakter sayısı ve kapladıkları alan bakımından kaynaklıdır.
Unicode'da her bir sembolün özel bir kodu bulunur ve biz bu kodları kullanarak programlarımıza entegre edebiliriz.
Kalp elde etmek için
print(`\u2665`)
-
- ASCII: Temel olarak İngilizce alfabesini ve birkaç temel sembolü içerir. Farklı dil ve kültürlerdeki özel karakterlere destek vermez.
- Unicode: Dünya genelinde birçok dil ve kültürü destekler, bu da metin ve sembollerin daha geniş bir yelpazesini temsil etmesine olanak tanır.
-
- 1 byte yani 8 bit alan kaplar.
true
yadafalse
ataması için kullanılır. Aynı zamandanull
değerde alabilir.- Bazı programlama dillerinde
0
veya1
de boolean olarak kabul edilebilir ama Kotlin'de kabul edilmez.
-
&& - and
- Eğer karşılaştırılan iki değer detrue
ise sonuçtrue
olur. Eğer ifadelerden herhangi birisifalse
isefalse
cevabını elde ederiz.val isAndroidDeveloper = true val isKeko:Boolean = false if(isAndroidDeveloper && isKeko){} if (isAndroidDeveloper and isKeko){} // Infix Fonksiyon İle Kullanımı if (isAndroidDeveloper.and(isKeko)){} // Extension Fonksiyon İle Kullanımı
|| - or
- Eğer karşılaştırılan iki değerden en az birisitrue
ise sonuçtrue
olur. Bu karşılaştırmadafalse
olması için iki değerindefalse
olması gerekiyor.val isAndroidDeveloper = true val isKeko:Boolean = false if(isAndroidDeveloper || isKeko){} if (isAndroidDeveloper or isKeko){} // Infix Fonksiyon İle Kullanımı if (isAndroidDeveloper.or(isKeko)){} // Extension Fonksiyon İle Kullanımı
! - not
- Bu operatör ile değerimiztrue
isefalse
,false
isetrue
yapar.val isAndroidDeveloper = true println(!isAndroidDeveloper) // Sonuç: false println(isAndroidDeveloper.not()) // Sonuç: false // Extension Fonksiyon İle Kullanımı
Boolean değerlerin
true
olma durumunu kontrol etmek için== true
şeklinde açıkca belirtmeye gerek yoktur. AmaNullable
olan değerler için açık bir şekilde kontrol işlemi gerçekleştirmeliyiz.if (isAndroidDeveloper) {}
Değişkenimiz
null
olduğunda artık 3 durumumuz var. Bunlartrue
,false
venull
olmasıval isSuccess: Boolean? = null if (isSuccess == true) { } else { // Geri kalan iki durum için else durumunu kullanır. }
-
&&
ve||
operatörleri Lazily çalışma mantığına sahiptir. Bu mantığa sahip olması demek;- Eğer
||
ile iki değeri kontrol ettiğimizde ilk değertrue
ise, ikinci değer hiçbir şekilde kontrol edilmez. Ama ilk değerfalse
ise, diğer ifadenin de kontrol işlemi gerçekleştirilir. - Eğer
&&
ile iki değeri kontrol ettiğimizde ilk değertrue
ise, ikinci değer de kontrol edilir. Ama ilk değerfalse
ise ikinci ifadenin kontrol işlemi gerçekleştirilmez.
- Eğer
-
- Yaklaşık olarak her karakter 2 byte (16 bits) yer kaplar.
- Çit tırnak
""
içerisine yazılan karakterler bütünüdür. String
bir değişken üzerindeki her bir karaktere index operatorü ile tek tek ulaşabiliriz.private val name = "Tolga" println(name[0]) // T -- Indexler 0 ile başlar println(name[1]) // o println(name[5]) // Tolga string ifadesi 5 length uzunluğuna sahip ama bu ifadenin son // karakterine ulaşmak istediğimizde indexini 4 olarak belirtmeliyiz. Çünkü indexlenen // ifadelerde index 0 (sıfır) ile başlar. // Olmayan bir index'e ulaşmak istediğimizde ise program bize StringIndexOutOfBoundsException hatasını // fırlatır.
-
String değişkenler immutabledır. Yani bir kez tanımlandıktan sonra, değerini değiştiremeyiz yada yeni bir değer set edilemez.
Şimdi aklımıza söyle bir soru gelmiş olabilir. Ben
var
keywordünü kullanarakString
tanımladıktan sonra o değişkenin değerini değiştirebiliyorum. Ama sen burada yeni bir değer atayamazsın ve değiştiremezsin diyorsun. Tam olarak anlayamadım diyebilirsin?Bunun arkasındaki yatan sebep
String
değişkenlerin bellekte saklanma durumlarından dolayıdır. Hatırlarsanız bu haftanın ilk sorusundaHEAP
veSTACK
kavramlarından bahsetmiştik. Reference değerli olan değişkenlerinvalue
larıHEAP
tarafında ve bu value değerini referans eden değişkenlerin iseStack
bölümünde tutulduğundan konuşmuştuk.String
değişkenlerin de değerleri primitive bir değişken olmasına rağmenHeap
bölümünde tutulur. Yani bizString
bir değişkene değer atadığımızdaHEAP
bölümünde yeni bir nesne oluşturulur ve değişkenimiz o nesneyi referans eder.String
üzerinde yapacağımız tüm işlemler bize yeni birstring
nesnesi dönecektir.val name = "Tolga" println(name.uppercase()) // TOLGA println(name) // Tolga name değişkeni üzerinde değişiklik yapmadı. // Eğer ben String bir ifade üzerinde işlem yaptıktan sonra, işlem gerçekleşmiş değişken // ile işlemlerime devam etmek istiyorum diyorsanız onu yeni bir değişkene atamamız gerekiyor. val nameUppercase = name.uppercase() println(nameUppercase) // TOLGA
-
- Farklı tipteki bir değişkenin önüne
String
bir değişken yada ifade koyarak toplarsak(+) operatörü ile, sonuçString
olacaktır. - Ancak bir
String
değişken yada ifadenin sonuna + operatörü ile farklı tipte bir değişken eklersek kod çalışmaz ve bize hata verecektir.
val numbersValue = "value" + (4+5+6) // value15 val numbersValue2 = (4+5+6) + "" // Hata verecektir.
Burada bu işlemin çalışmamasının arkasındaki sebep
String
değişkenlerinplus
operatör fonksiyonuna baktığımızdaAny
tipine sahip değişkenleri kabul ederkenInt
değişkeninplus()
operatör fonksiyonuByte,Short,Int,Float,Double
kabul ediyor. - Farklı tipteki bir değişkenin önüne
-
Kotlin'de herhangi bir değişken
+
operatörüne ihtiyaç duyulmadan direkt olarak""
(çift tırnak) arasına yazılarak kullanılabilir. -
Bunun için
$
işaretine ihtiyacımız vardır. Bu yapıya String Template denir.val age = 23 println("Age: $age") // Age: 23
-
Eğer değişkenin herhangi bir özelliğine erişmek istiyorsanız
${}
ile kullanılır.val name = "Tolga" println("$name.length: ${name.length}") // Tolga.length: 5
-
- Bu method, belirli bir
String
içinde yer tutucuları(placeholder) belirtilen değerlerle değiştirerek yeni birString
oluşturmamıza olanak tanır.
Kotlin'deki
format()
fonksiyonu arka planda Javadaki format fonksiyonunu kullanır.Placeholders:
%s
: String%d
Integer için%f
Float/Double%n
Yeni bir satıra geçmek için
val boy = 1.854 val boyMessage = String.format("Boyum: %.2f metre", boy) println(boyMesaj)
Burada 1.85 döndürür. Sondaki 4'ü almaz Çünkü biz 2 ondalık basamak kısmını al dedik. 2f 2 ondalık basamakla olduğunu belirtir. Noktadan sonra ne kadar ifade alacağını belirtmiş olduk.
val sayi = 1234567.8954768 val usFormat = String.format(Locale.US, "US formatında: %,.2f", sayi) // //Türkçe için Locale nesnesi, "tr" ISO 639 dil kodu ve "TR" ISO 3166 Ülke kodu ile oluşturulabilir val localeTR = Locale("tr", "TR") // Türkçe için Locale nesnesi oluşturuluyor. val trFormat = String.format(localeTR, "TR formatında: %,.2f", sayi) print(usFormat) // US formatında: 1,234,567.89" yazdırır. print(trFormat) // TR formatında: 1.234.567,90" yazdırır.
Peki burada ki
,.2f
kısmındaki ilk virgül neyi temsil ediyor. Yukarıdaki sayı değeri ingilizce de normalde1,234,567.8954768
bu şekilde olduğu için yani yüzdelik kısımları ayırmak için,
, ondalık kısımları ayırmak için.
kullanılıyor. Buradaki ilk,
ifadesi sayıdaki,
kısımlarını temsil etmiş oluyor. (Programlama İngilizce diline göre geliştirildiği için öyle kabul edilmiş) Yani biz bu fonksiyonda diyoruz ki ben bu formatta o kısımlara,
koyacağım ama bunu Türkçeye göre yap. - Bu method, belirli bir
-
Array'ler aynı türden veya interface yapısı
<>
içerisinde belirttiğimiz türün alt türlerinden sabit sayıda değer tutan bir veri yapısıdır.-
Kotlin'de array oluşturmak istediğimizde iki tane seçenek önümüze çıkar. Bunlardan birisi
Object Type Array
bir diğeri isePrimitive Type Array
'dir. Bunların arasındaki temel fark yine bellekte nasıl saklandıkları ile ilgilidir. VePrimitive Type
olan türler her zamanObject Type
olan türlere göre daha performanslı, daha hızlı ve daha az yer kapladığı için bunları tercih etmeliyiz.-
Object Type Array oluşturmak için bize sunulan birçok yöntem bulunuyor. Bunlar;
arrayOf()
: Hepsi aynı tipte olan veya birAny
(Bu şu anda Any ama biz ileride class yapılarını gördüğümüzde kendi oluşturmuş olduğumuz classlarıda verebileceğiz.) ile belirtilmiş alt türleri de kabul eden array oluşturmak için kullanılır.
val studentNumbers = arrayOf(13, 14, 15, 16) // Int Array val studentNames = arrayOf("Ömer", "Arda", "Doğaç") // String Array val studentHeight = arrayOf(185.3, 184.3, 180.0) // Double Array val differentTypeArray = arrayOf<Any>("Tolga", true, 23, 2.0)
arrayOfNulls<Type>(size)
: Verilensize
bilgisi kadarnull
değer bulunduran array oluşturmak için kullanılır.
val arrayOfNulls = arrayOfNulls<String>(5) println("arrayOfNulls: ${arrayOfNulls.joinToString()}") // Çıktı: arrayOfNulls: null, null, null, null, null
joinToString() Fonksiyonu: Array içerisindeki elemanları aldığı bir seperator ile ayırarak
String
ifade döner.Seperator
varsayılan olarakvirgül(,)
karakteridir.emptyArray<Type>()
: Bu fonksiyon ile boş bir array oluştururuz
val emptyArray = emptyArray<Int>() println("emptyArray: ${emptyArray.joinToString()}") // Çıktı: emptyArray: Boş olduğu için harhangi bir şey gösterilmiyor.
emptyArray[3] = 60
diyerek bir eleman eklemeye çalıştığımızdaArrayIndexOutOfBoundsException
hatasını alırız. Çünkü bu arrayin kaç değere sahip olacağını belirtmedik. Bu dizi aslında boş bir dizi olduğu için, bellekte bir dizi elemanı için yer ayrılmaz. Yani, bu durumda, sadece boş bir dizi referansı oluşturulmuş olur ve herhangi bir eleman içermez.- Constructor Yapısı ile
Array(size)
val studentNotes = Array(5){ // Bazı işlemler yapılabilir it + 40 } println(studentNotes.joinToString()) // 40,41,42,43,44
Bu örnekte, Array(5) ifadesi 5 elemanlı bir array oluşturur. Süslü parantezler(higherOrder) içindeki kod bloğu her bir index değeri ile (it) ile 40 ekleyerek bir array oluşturur.
-
-
- Constructor Yapısı İle Oluşturma
val booleanPrimitiveArray = BooleanArray(3) val bytePrimitiveArray = ByteArray(3) val charPrimitiveArray = CharArray(3) val doublePrimitiveArray = DoubleArray(3) val floatPrimitiveArray = FloatArray(3) val intPrimitiveArray = IntArray(3) val longPrimitiveArray = LongArray(3) val shortPrimitiveArray = ShortArray(3) println("booleanPrimitiveArray: ${booleanPrimitiveArray.joinToString()}") println("bytePrimitiveArray: ${bytePrimitiveArray.joinToString()}") println("charPrimitiveArray: ${charPrimitiveArray.joinToString()}") println("doublePrimitiveArray: ${doublePrimitiveArray.joinToString()}") println("floatPrimitiveArray: ${floatPrimitiveArray.joinToString()}") println("intPrimitiveArray: ${intPrimitiveArray.joinToString()}") println("longPrimitiveArray: ${longPrimitiveArray.joinToString()}") println("shortPrimitiveArray: ${shortPrimitiveArray.joinToString()}")
Bu şekilde oluşturduğumuzda oluşturulan array'ler default değerler ile oluşturuluyor. Yukarıdaki yazdırdığımız işlemlerin çıktıları aşağıdaki gibi olacaktır.
booleanPrimitiveArray: false, false, false bytePrimitiveArray: 0, 0, 0 doublePrimitiveArray: 0.0, 0.0, 0.0 floatPrimitiveArray: 0.0, 0.0, 0.0 intPrimitiveArray: 0, 0, 0 longPrimitiveArray: 0, 0, 0 shortPrimitiveArray: 0, 0, 0
- Fonksiyonlar İle Oluşturma
val booleanPrimitiveArray2 = booleanArrayOf(true, false, true, true) val bytePrimitiveArray2 = byteArrayOf() val charPrimitiveArray2 = charArrayOf('A', 'B', 'C') val doublePrimitiveArray2 = doubleArrayOf() val floatPrimitiveArray2 = floatArrayOf() val intPrimitiveArray2 = intArrayOf(3, 4, 67) val longPrimitiveArray2 = longArrayOf() val shortPrimitiveArray2 = shortArrayOf()
Bize sunulan hazır fonksiyonlar ilede bir array oluşturabiliriz. Fonksiyon içerisinde herhangi bir değer vermezsek bize boş bir array oluşturur. Ama bizim istediğimiz değerler ile bir array oluşturulmasını istiyorsak o değerleri de fonksiyon parametresine argüman olarak verilebilir.
-
Primitive type
olan bir array'iObject Type
olan array'e dönüştürmek içintoTypedArray()
fonksiyonu kullanılır.val convertPrimitiveToObjectType = booleanPrimitiveArray.toTypedArray() // Artık bu array'imiz Array<Boolean> olacaktır.
Object Type
olan bir array'iPrimitive Type
olan bir array'e dönüştürmek için aşağıda belirtilen fonksiyonları kullanabiliriz:`toBooleanArray()`: Boolean primitive bir array'e dönüştürmek için kullanılır. `toByteArray()`: Byte primitive bir array'e dönüştürmek için kullanılır. `toCharArray()`: Char primitive bir array'e dönüştürmek için kullanılır. `toDoubleArray()`: Double primitive bir array'e dönüştürmek için kullanılır. `toFloatArray()`: Float primitive bir array'e dönüştürmek için kullanılır. `toIntArray()`: Int primitive bir array'e dönüştürmek için kullanılır. `toLongArray()`: Long primitive bir array'e dönüştürmek için kullanılır. `toShortArray()`: Short primitive bir array'e dönüştürmek için kullanılır.
-
val twoDArray = Array(2) { Array(2) { 0 } } println("TwoD Array: ${twoDArray.contentDeepToString()}") // [[0,0], [0,0]] val threeDArray = Array(2) { Array(2) { Array(2) { 0 } } } println("ThreeD Array: ${threeDArray.contentDeepToString()}") // [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]
contentDeepToString()
fonksiyonu çok boyutlu olan bir diziyi // [[0,0], [0,0]] şekilde ekrana yazdıran bir fonksiyondur.
-
-
Array'lerde
==
operatörü referans kontrolü yapıyor. Yani iki değişken de aynı referansına sahip olduğu kontrolü yapılıyor.Ama biz arraylerin içerisindeki değerlerin aynı olup olmadığı karşılaştırmasını yapmak istersek
contentEquals
yadacontentDeepEquals
kullanmalıyız.Bu iki yöntem de: Karşılaştırılan iki array arasında hem aynı değerlere sahip olup olmadığını hemde aynı sırada bulunup bulunmadığını karşılaştırırç
val simpleArray = arrayOf(1, 2, 3) val anotherArray = arrayOf(1, 2, 3) println("== İle Yapılan Karşılaştırma: ${simpleArray == anotherArray}") // false println("contentEquals() İle Yapılan Karşılaştırma: ${simpleArray.contentEquals(anotherArray)}") // true println(simpleArray contentEquals anotherArray) // İnfix olarak kullanımı
-
Array'lerin sabit bir büyüklüğü olduğundan bahsetmiştik. Array'lere ekleme, çıkarma işlemleri yaptığımızda Stringler'de olduğu gibi bellekte yeni bir array oluşturulur ve bizim değişkenimiz yeni oluşturulan array'in reference adresini tutar. Diğer array ise GarbageCollector ile belli bir zaman sonra yok edilecektir.
var cities = arrayOf("Kayseri", "İstanbul", "İzmir") println("Cities Before Add Sivas: ${cities.joinToString()}") cities += "Sivas" // Adding Sivas println("Cities After Add Sivas: ${cities.joinToString()}") // Veya bu şekilde yani bir array eklemesi de yapılabilir. cities += arrayOf("Nevşehir", "Bursa") println("Cities After Add New Cities Array: ${cities.joinToString()}") // Çıktılar: // Cities Before Add Sivas: Kayseri, İstanbul, İzmir // Cities After Add Sivas: Kayseri, İstanbul, İzmir, Sivas // Cities After Add New Cities Array: Kayseri, İstanbul, İzmir, Sivas, Nevşehir, Bursa
val
ile tanımlanmış bir arrayin herhangi bir index'deki değerini [] index operatörü ile değiştirebiliriz.val
indexdeki değerlerin değişmesine karışmaz. Ancak bir array'ival
ile tanımlanmış bir değişkene atamasını yapamayız.val array3 = arrayOf(1, 2, 3, 4) println("Before Modify array3: ${array3.joinToString()}") array3[2] = 10 // Array'deki 2. indesde bulunan değeri 10 ile değiştirdim. println("After Modify array3 ${array3.joinToString()}") // Çıktılar // Before Modify array3: 1, 2, 3, 4 // After Modify array3: 1, 2, 10, 4
-
Array'Ler invariantdır. Yani arrayler üst class'ları yerine atanamazlar.
val arrayOfString = arrayOf("") var arrayOfAny: Array<Any> = arrayOfString // Burada bize bir type mismatch hatasını verecektir.
-
vararg
keyword'ü ile fonksiyonlarımızda istediğimiz sayıda parametre kabul edilebilir. Eğervararg
a denk gelecek şekilde bir array kullanmak istiyorsakspread *
operatörünü kullanabiliriz.vararg
konusunu ileride fonksiyonlarda daha detaylı bir şekilde göreceğiz.fun printAllStrings(vararg strings: String) { for (string in strings) { print(string) } } val lettersArray = arrayOf("c", "d") printAllStrings("a", "b", *lettersArray)
-
Array'lerde Collections yapılarında kullandığımız birçok yardımcı fonksiyonu da kullanabiliyoruz. Bunlardan bazıları
filter, first, last, find, shuffle
ve çok daha fazlası.Bütün fonksiyonlara bakmak isterseniz: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/
val students = arrayOf("Tolga", "Gökhan", "Ömer", "Arda", "Barış", "Ayşe") val studentWithStartingA = students.filter { it.first() == 'A' } println("Student Starting name with A $studentWithStartingA") val numbers = arrayOf(1, 2, 3, 4, 5) numbers.shuffle() println("Shuffled Numbers: ${numbers.joinToString()}") // Çıktılar // Student Starting name with A: [Arda, Ayşe] // Shuffled Numbers: 2, 3, 1, 5, 4 // Bu çıktı her seferinde farklı sonuçlar alabilir.
-
Kullandığımız array yapılarını
set
,list
vemap
veri yapılarına dönüştürebiliriz.Set
yapısı içerisinde değer olarak, benzersiz elemanları içeren bir yapıdır. O yüzden array'i set'e çevirdiğimizde ve print ettiğimizde sadece a,b,c göreceğiz ikinci c'i göremeyiz.val simpleArray = arrayOf("a", "b", "c", "c") println("Converted to Set: ${simpleArray.toSet()}") println("Converted to MutableSet: ${simpleArray.toMutableSet()}") // a, b, c
toList
fonksiyonunu kullanarak Liste yapısına çevirebiliriz. Aynı şekilde eğer bu liste yapımızda ekleme çıkarma işlemleri yapmamızda gerekiyorsa o zamantoMutableList()
fonksiyonu ile mutable bir list oluşturabiliriz.val simpleArray = arrayOf("a", "b", "c", "c") println("Converted to List: ${simpleArray.toList()}") println("Converted to MutableList: ${simpleArray.toMutableList()}")
Array'leri Map veri yapısına dönüştürmek için
toMap()
fonksiyonunu kullanabiliriz. Yalnız arrayleriMap
'e çevirebilmemiz için array içerisindeki değerlerPair<K,V>
formunda olması gerekiyor. Pair çiftleri bir değerikey-value
formatında saklamak için kullanılır.Pair
oluşturmak içinPair("Tolga", 23)
veyato
infix notasyonu ile de oluşturabiliriz."Tolga" to 23"
val pairArray = arrayOf("Tolga" to 23, "Ahmet" to 25, "Sena" to 20) println("Converted to Map: ${pairArray.toMap()}") // Converted to Map: {Tolga=23, Ahmet=25, Sena=20}
Pair
sadece iki eleman içerir. İçerisindekey - value
şeklinde bir değer tutar.Map
ise içerisinde birden fazlaPair
çiftlerini içerir.- Kısacası, Pair tek bir
key-value
çiftini temsil ederken, Map birçokkey-value
çiftini içeren bir koleksiyonu temsil eder.
-
-
- Eğer veri setinizin boyutu önceden belirlenmiş ve bu boyut ekleme veya çıkarma işlemleriyle değişmeyecekse,
array
'ler uygun bir seçenek olabilir. Bu bilgilerle birlikte primitive array yapıları da oluşturabildiğimiz için performans artırabilirler. Ama veri setimiz dinamik bir şekilde değişiyorsa o zaman Collections yapılarını kullanmak daha mantıklı bir seçenek olacaktır. - Ancak, veri setinizin boyutunun değişebileceği durumlarda veya dinamik veri manipülasyonları gerekiyorsa,
Collections
yapıları gibi dinamik boyutlu veri yapıları daha uygun olabilir.
- Eğer veri setinizin boyutu önceden belirlenmiş ve bu boyut ekleme veya çıkarma işlemleriyle değişmeyecekse,
Sonlu sayıda liste oluşturmak için kullanılır.
-
Küçükten büyüğe bir range oluşturmak için kullanılan birkaç yöntem vardır:
..
operatörü yadarangeTo
fonksiyonu - Bu şekilde oluşturduğumuz range'de belirttiğimiz her iki elemanda dahil olur...<
operatörü yadarangeUntil()
fonksiyonu : Bu şekilde oluşturduğumuz range'de belirttiğimiz ilk eleman dahil son eleman dahil olmaz.until()
fonksiyonu ile oluşturabiliriz.val numbers = 1..100 // [1,100] val numbers2 = 1.rangeTo(100) val numbersUntil = 1..<100 //[1,100) val numbersUntil2 = 1.rangeUntil(100) /// 1,2,3,4,...,99 val gradeNumbers = 30.until(90) val gradeNumbers2 = 30 until 90 // 30,31,32 .... 89
step
fonksiyonu kullanarak liste olustururken belli sayıda atlamalar yapabiliriz.val numbers = 1..100 step 2 val numbers2 = 1.rangeTo(100) step 2 // 1,3,5,7.....99 val numbersUntil = 1..<100 step 3 val numbersUntil2 = 1.rangeUntil(100) step 3 // 1,4,7,10,13 .... 97 val gradeNumbers = 30.until(90) step 5 val gradeNumbers2 = 30 until 90 step 5 // 30,35,40,45 .... 85
Char
'lardan oluşan bir liste de tanımlayabiliriz. Türkçe karakterler içermez.val alphabet = 'A'..'Z' alphabet.forEach { print("$it ") } // A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
-
-
Büyükten küçüğe bir range oluşturmak için
downTo()
fonksiyonu kullanılır.val reversedNumbers = 100.downTo(1) val reversedNumbers2 = 100 downTo 1 // 100,99,98 ... 1 val reversedNumbersStep2 = 100 downTo 1 step 2 // 100, 98, 96 ... 2
-
CharRange
,IntRange
veLongRange
isimlerinde özel rangeler vardır.Progression olarak adlandırılırlar -
Bu durumda
first
,last
,step
,count
gibi ek özelliklerine ulaşabiliriz. -
Iterable<N>
interfacesini implement etmişlerdir .O sebeplemap
,filter
gibi fonksiyonları kullanabiliriz.val numbers:IntProgression = 1..100 step 2 // 1,3,5,7 ... 99 println("NumberRange First:${numbers.first}") println("NumberRange Last:${numbers.last}") println("NumberRange Step:${numbers.step}") println("NumberRange Count:${numbers.count()}") /* Çıktı: NumberRange First:1 NumberRange Last:99 NumberRange Step:2 NumberRange Count:50 */
-