Kotlin, her yerde Android geliştiricileri tarafından yaygın olarak kullanılan bir programlama dilidir. Bu konu, kısa sürede hazırlayıp kullanmaya başlamanızı sağlayacak bir Kotlin atlama kursu işlevi görüyor.
Değişken bildirimi
Kotlin, değişkenleri bildirmek için iki farklı anahtar kelime kullanır: val
ve var
.
- Değeri asla değişmeyen bir değişken için
val
kullanın. Bir değeri,val
kullanılarak tanımlanan bir değişkene yeniden atayamazsınız. - Değeri değişebilen bir değişken için
var
kullanın.
Aşağıdaki örnekte count
, başlangıç değeri 10
olan Int
türünde bir değişkendir:
var count: Int = 10
Int
, Kotlin'de temsil edilebilen birçok sayısal türden biri olan tam sayıyı temsil eden bir türdür. Diğer dillere benzer şekilde, sayısal verilerinize bağlı olarak Byte
, Short
, Long
, Float
ve Double
dillerini de kullanabilirsiniz.
var
anahtar kelimesi, değerleri gerektiği gibi count
öğesine yeniden atayabileceğiniz anlamına gelir. Örneğin, count
değerini 10
yerine 15
olarak değiştirebilirsiniz:
var count: Int = 10
count = 15
Yine de bazı değerlerin değiştirilmesi amaçlanmamıştır. languageName
adlı bir String
kullanmayı düşünün. languageName
parametresinin her zaman "Kotlin" değerine sahip olmasını istiyorsanız val
anahtar kelimesini kullanarak languageName
özelliğini belirtebilirsiniz:
val languageName: String = "Kotlin"
Bu anahtar kelimeler, nelerin değiştirilebileceğini açıkça belirtmenize olanak tanır. Bunları kendi yararınıza
kullanabilirsiniz. Bir değişken referansının yeniden atanabilir olması gerekiyorsa bunu var
olarak bildirin. Aksi takdirde val
alanını kullanın.
Çıkarımı yazın
Önceki örnekten devam edersek languageName
öğesine başlangıç değeri atadığınızda Kotlin derleyicisi, atanan değerin türüne göre türü tahmin edebilir.
"Kotlin"
değeri String
türünde olduğundan derleyici, languageName
değerinin aynı zamanda bir String
olduğu sonucuna varır. Kotlin'in statik olarak yazılmış bir dil olduğunu unutmayın. Bu, türün derleme zamanında çözümlendiği ve hiçbir zaman değişmediği anlamına gelir.
Aşağıdaki örnekte languageName
, String
olarak tahmin edildiği için String
sınıfının parçası olmayan işlevleri çağıramazsınız:
val languageName = "Kotlin"
val upperCaseName = languageName.toUpperCase()
// Fails to compile
languageName.inc()
toUpperCase()
, yalnızca String
türündeki değişkenlerde çağrılabilen bir işlevdir. Kotlin derleyicisi languageName
değerini String
olarak tahmin ettiği için toUpperCase()
yöntemini güvenle çağırabilirsiniz. Ancak inc()
, Int
operatör işlevi olduğundan String
üzerinde çağrılamaz. Kotlin'in tür çıkarıma yaklaşımı size hem kısa netlik hem de tür güvenliği sağlar.
Boş güvenlik
Bazı dillerde, referans türü değişkeni başlangıçtaki açık bir değer sağlanmadan bildirilebilir. Bu durumlarda, değişkenler genellikle null değer içerir. Kotlin değişkenleri varsayılan olarak boş değerler içeremez. Bu, aşağıdaki snippet'in geçersiz olduğu anlamına gelir:
// Fails to compile
val languageName: String = null
Bir değişkenin null değer alabilmesi için nullable türünde olması gerekir. Bir değişkeni aşağıdaki örnekte gösterildiği gibi, türünü ?
ile ekleyerek boş değer atanabilir olarak belirtebilirsiniz:
val languageName: String? = null
String?
türü sayesinde languageName
adlı kullanıcıya String
değeri veya null
atayabilirsiniz.
Boş değerli değişkenleri dikkatli bir şekilde ele almanız gerekir. Aksi halde, korkunç bir NullPointerException
riski söz konusu olabilir. Örneğin, Java'da bir yöntemi null değeriyle çağırmaya çalışırsanız programınız kilitlenir.
Kotlin, null değişkenlerle güvenli bir şekilde çalışmak için çeşitli mekanizmalar sunar. Daha fazla bilgi için Android'de Yaygın Kotlin kalıpları: Nullability bölümüne bakın.
Koşullar
Kotlin, koşullu mantığı uygulamak için çeşitli mekanizmalar içerir. Bunların en yaygını if-else ifadesidir. Bir if
anahtar kelimesinin yanında parantez içine alınmış bir ifade true
olarak değerlendirilirse bu dalın içindeki kod (ör. hemen ardından gelen, süslü parantez içine sarmalanmış kod) yürütülür. Aksi takdirde, else
dalı içindeki kod yürütülür.
if (count == 42) {
println("I have the answer.")
} else {
println("The answer eludes me.")
}
Birden çok koşulu else if
kullanarak temsil edebilirsiniz. Bu, aşağıdaki örnekte gösterildiği gibi tek bir koşullu ifadede daha ayrıntılı ve karmaşık bir mantığı temsil etmenize olanak tanır:
if (count == 42) {
println("I have the answer.")
} else if (count > 35) {
println("The answer is close.")
} else {
println("The answer eludes me.")
}
Koşullu ifadeler, durum bilgili mantığı temsil etmek için kullanışlıdır ancak
bunları yazarken kendinizi tekrarlayabilirsiniz. Yukarıdaki örnekte, her dalda bir String
yazdırmanız yeterlidir. Kotlin bu tekrarı önlemek için koşullu ifadeler sunar. Son örnek şu şekilde yeniden yazılabilir:
val answerString: String = if (count == 42) {
"I have the answer."
} else if (count > 35) {
"The answer is close."
} else {
"The answer eludes me."
}
println(answerString)
Dolaylı olarak, her koşullu dal, ifadenin sonucunu son satırında döndürür, böylece return
anahtar kelimesi kullanmanıza gerek yoktur. Üç dalın tamamının sonucu String
türünde olduğundan if-else ifadesinin sonucu da String
türünde olur. Bu örnekte, answerString
öğesine if-else ifadesinin sonucundan bir başlangıç değeri atanır. Tür çıkarımı, answerString
için açık tür bildirimini atlamak için kullanılabilir ancak açıklık sağlamak için genellikle bunu dahil etmek iyi bir fikirdir.
Koşullu ifadenizin karmaşıklığı arttıkça, if-else ifadenizi aşağıdaki örnekte gösterildiği gibi when ifadesiyle değiştirmeyi düşünebilirsiniz:
val answerString = when {
count == 42 -> "I have the answer."
count > 35 -> "The answer is close."
else -> "The answer eludes me."
}
println(answerString)
when
ifadesindeki her dal; bir koşul, ok (->
) ve bir sonuçla temsil edilir. Okun sol tarafındaki koşul doğru olarak değerlendirilirse sağ taraftaki ifadenin sonucu döndürülür. Yürütmenin bir daldan diğerine geçmediğini unutmayın.
when
ifade örneğindeki kod, işlevsel olarak önceki örnektekiyle eşdeğerdir ancak muhtemelen daha kolay okunur.
Kotlin’in koşullu özellikleri, en güçlü özelliklerinden biri olan akıllı yayınlama özelliğini öne çıkarır. Boş değerlerle çalışmak için güvenli arama operatörünü veya null olmayan onay operatörünü kullanmak yerine, bunun yerine, aşağıdaki örnekte gösterildiği gibi bir değişkenin koşullu ifade kullanarak null değerine referans içerip içermediğini kontrol edebilirsiniz:
val languageName: String? = null
if (languageName != null) {
// No need to write languageName?.toUpperCase()
println(languageName.toUpperCase())
}
Koşullu dal içinde languageName
, boş değer atanamaz olarak değerlendirilebilir.
Kotlin, dalı yürütme koşulunun, languageName
null değer içermemesi olduğunu kabul edecek kadar akıllıdır. Bu nedenle, languageName
öğesini bu dal içinde null özellikli olarak değerlendirmeniz gerekmez. Bu akıllı yayınlama boş kontroller, tür kontrolleri veya bir sözleşmeyi karşılayan tüm koşullar için çalışır.
Fonksiyonlar
Bir veya daha fazla ifadeyi bir işlev halinde gruplandırabilirsiniz. Bir sonuca ihtiyacınız olduğunda her defasında aynı ifade dizisini tekrarlamak yerine, ifadeleri bir fonksiyon içinde sarmalayabilir ve bunun yerine o işlevi çağırabilirsiniz.
Bir işlevi tanımlamak için fun
anahtar kelimesini ve ardından işlev adını kullanın.
Ardından, işlevinizin aldığı giriş türlerini (varsa) ve döndürdüğü çıkış türünü tanımlayın. Bir işlevin gövdesinde, işleviniz çağrıldığında çağrılan ifadeleri tanımladığınız yerdir.
Önceki örneklere dayanarak, eksiksiz bir Kotlin işlevi görebilirsiniz:
fun generateAnswerString(): String {
val answerString = if (count == 42) {
"I have the answer."
} else {
"The answer eludes me"
}
return answerString
}
Yukarıdaki örnekte bulunan işlev generateAnswerString
adına sahiptir. Herhangi bir girdi gerektirmez. String
türünde bir sonuç verir. Bir işlevi çağırmak için işlevin adını ve ardından çağrı operatörünü (()
) kullanın. Aşağıdaki örnekte answerString
değişkeni, generateAnswerString()
sonucuyla başlatılır.
val answerString = generateAnswerString()
İşlevler, aşağıdaki örnekte gösterildiği gibi girdi olarak bağımsız değişkenler alabilir:
fun generateAnswerString(countThreshold: Int): String {
val answerString = if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
return answerString
}
Bir işlevi tanımlarken, istediğiniz sayıda bağımsız değişken ve bunların türlerini belirtebilirsiniz. Yukarıdaki örnekte generateAnswerString()
, Int
türünde countThreshold
adlı bir bağımsız değişkeni alır. İşlev içinde, adını kullanarak bağımsız değişkene başvurabilirsiniz.
Bu işlevi çağırırken işlev çağrısının parantezlerinin içine bir bağımsız değişken eklemeniz gerekir:
val answerString = generateAnswerString(42)
Fonksiyon ifadelerini basitleştirme
generateAnswerString()
oldukça basit bir işlevdir. İşlev bir değişken tanımlar ve hemen geri döner. Tek bir ifadenin sonucu bir işlevden döndürüldüğünde, aşağıdaki örnekte gösterildiği gibi, işlevde yer alan if-else ifadesinin sonucunu doğrudan döndürerek yerel değişken bildirmeyi atlayabilirsiniz:
fun generateAnswerString(countThreshold: Int): String {
return if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
}
Return anahtar kelimesini atama operatörüyle de değiştirebilirsiniz:
fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
"I have the answer"
} else {
"The answer eludes me"
}
Anonim işlevler
Her işlevin adı yoktur. Bazı fonksiyonlar girdi ve çıktılarıyla daha doğrudan tanımlanır. Bu işlevlere anonim işlevler denir. Daha sonra anonim işlevi çağırmak için bu referansı kullanarak anonim bir işleve referans tutabilirsiniz. Referansı, diğer referans türlerinde olduğu gibi uygulamanızın etrafında da aktarabilirsiniz.
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
Adlandırılmış işlevlerde olduğu gibi anonim işlevler de istediğiniz sayıda ifade içerebilir. İşlevin döndürülen değeri, son ifadenin sonucudur.
Yukarıdaki örnekte stringLengthFunc
, giriş olarak String
alan ve String
girdisinin uzunluğunu Int
türünün çıktısı olarak döndüren anonim bir işleve referans içerir. Bu nedenle, işlevin türü (String) -> Int
olarak belirtilir. Ancak bu kod işlevi çağırmaz.
İşlevin sonucunu almak için, söz konusu işlevi adlandırılmış bir işlevde olduğu gibi çağırmanız gerekir. stringLengthFunc
çağırırken aşağıdaki örnekte gösterildiği gibi bir String
sağlamanız gerekir:
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
val stringLength: Int = stringLengthFunc("Android")
Üst düzey işlevler
Bir işlev, başka bir işlevi bağımsız değişken olarak alabilir. Bağımsız değişken olarak diğer işlevleri kullanan işlevler, üst düzey işlevler olarak adlandırılır. Bu kalıp, Java'da geri çağırma arayüzünü kullandığınız şekilde bileşenler arasında iletişim kurmak için kullanışlıdır.
Aşağıda, üst düzey bir işleve ilişkin bir örnek verilmiştir:
fun stringMapper(str: String, mapper: (String) -> Int): Int {
// Invoke function
return mapper(str)
}
stringMapper()
işlevi, bir String
işlevini, ilettiğiniz bir String
öğesinden Int
değeri türeten bir işlevle birlikte alır.
Aşağıdaki örnekte gösterildiği gibi, bir String
ve diğer giriş parametresini karşılayan bir işlev (giriş olarak String
alıp Int
döndüren bir işlev) ileterek stringMapper()
çağırabilirsiniz:
stringMapper("Android", { input ->
input.length
})
Anonim işlev, bir işlevde tanımlanan last parametresiyse bu parametreyi, aşağıdaki örnekte gösterildiği gibi, işlevi çağırmak için kullanılan parantezlerin dışına geçirebilirsiniz:
stringMapper("Android") { input ->
input.length
}
Kotlin standart kitaplığında anonim işlevler bulunabilir. Daha fazla bilgi için Yüksek Sıralı İşlevler ve Lambda'lar bölümüne bakın.
Sınıflar
Şimdiye kadar bahsi geçen türlerin tümü Kotlin programlama dilinde yerleşiktir. Kendi özel türünüzü eklemek isterseniz aşağıdaki örnekte gösterildiği gibi class
anahtar kelimesini kullanarak bir sınıf tanımlayabilirsiniz:
class Car
Kod
Sınıflar, özellikleri kullanarak durumu temsil eder. Özellik; alıcı, setter ve geri alan içerebilen sınıf düzeyinde bir değişkendir.
Bir arabada sürüş için tekerlek kullanılması gerektiğinden, aşağıdaki örnekte gösterildiği gibi Wheel
nesnelerinin bir listesini Car
özelliği olarak ekleyebilirsiniz:
class Car {
val wheels = listOf<Wheel>()
}
wheels
öğesinin bir public val
olduğunu, yani wheels
öğesine Car
sınıfının dışından erişilebildiğini ve yeniden atanamayacağını unutmayın. Car
örneği elde etmek istiyorsanız önce kurucusunu çağırmanız gerekir. Buradan erişilebilir
özelliklerine erişebilirsiniz.
val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car
Tekerleklerinizi özelleştirmek istiyorsanız sınıf özelliklerinin nasıl başlatılacağını belirten bir özel oluşturucu tanımlayabilirsiniz:
class Car(val wheels: List<Wheel>)
Yukarıdaki örnekte, sınıf oluşturucu, List<Wheel>
özelliğini kurucu bağımsız değişkeni olarak alır ve wheels
özelliğini başlatmak için bu bağımsız değişkeni kullanır.
Sınıf işlevleri ve kapsülleme
Sınıflar, davranışı modellemek için işlevleri kullanır. Functions, durumu değiştirerek yalnızca göstermek istediğiniz verileri göstermenize yardımcı olur. Bu erişim denetimi, kapsülasyon olarak bilinen daha geniş nesne odaklı bir kavramın parçasıdır.
Aşağıdaki örnekte doorLock
özelliği, Car
sınıfının dışındaki her şeyden gizli tutulur. Arabanın kilidini açmak için aşağıdaki örnekte gösterildiği gibi geçerli bir anahtarda geçen unlockDoor()
işlevini çağırmanız gerekir:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
Bir mülke referans verildiğini özelleştirmek isterseniz özel alıcı ve ayarlayıcı sağlayabilirsiniz. Örneğin, bir mülkün alıcısını, ayarlayıcısına erişimi kısıtlarken açığa çıkarmak isterseniz bu ayarlayıcıyı private
olarak tanımlayabilirsiniz:
class Car(val wheels: List<Wheel>) {
private val doorLock: DoorLock = ...
var gallonsOfFuelInTank: Int = 15
private set
fun unlockDoor(key: Key): Boolean {
// Return true if key is valid for door lock, false otherwise
}
}
Özelliklerin ve işlevlerin bir kombinasyonunu kullanarak her tür nesneyi modelleyen sınıflar oluşturabilirsiniz.
Birlikte çalışabilirlik
Kotlin’in en önemli özelliklerinden biri, Java ile akıcı bir şekilde birlikte çalışabilmesidir. Kotlin kodu JVM bayt koduna göre derlendiğinden Kotlin kodunuz doğrudan Java kodunu, bunun tersi de geçerlidir. Yani mevcut Java kitaplıklarından doğrudan Kotlin'den yararlanabilirsiniz. Dahası, Android API'lerinin çoğu Java'da yazılır ve doğrudan Kotlin'den çağırabilirsiniz.
Sonraki adımlar
Kotlin, sunduğu destek ve ivmeyle esnek ve pragmatik bir dildir. Henüz denemediyseniz bunu denemenizi öneririz. Sonraki adımlar için Android uygulamalarınızda yaygın Kotlin kalıplarını uygulama kılavuzuyla birlikte resmi Kotlin dokümanlarına göz atın.