Kotlin alapú szoftverfejlesztés - 4. előadás¶
Null-ok¶
class Person(val name: String)
fun main() {
val person: Person = null //ilyet nem tudok, mert a Person-ba nem fér a null!
val person2: Person? = null //nullable típus, azaz ez Person vagy null is lehet!
println(person.name) //így nem tudunk akármilyen függvényhívást!
if(person != null) {
println(person.name) //kaptunk egy smart cast-ot, mert a feltétel bizonyítja, hogy nem null
}
person?.name //safe call operátor
//ha a bal oldalán null van, kihagyja a hívást, és null-lesz az egész értéke
//ha bal oldalt helyes érték van, akkor meghívódik a függvény
val name: String? = person?.name //példa a használatára
println(person?.company?.address?.building) //így lehet láncolni ezt
}
- Elvis operator (?:), null coalescing operator
fun main() {
val message: String? = readLine()
val length = message?.length ?: 0 //ha a message null, akkor 0-t ad vissza
}
//egy még szebb megoldás:
fun processInput() {
while(true) {
val input: String = readLine() ?: return
println("Read ${input.length} characters from input")
}
}
-
null safety kikapcsolása (!!)
val persin: Person? = Person("Jim") println(person!!.name) //a !! leszedi a kérdőjelt, ha meg null, dob egy null pointer exception-t! -
safe cast (as?)
for(entity in entities) { (entity as? Renderable)?.render(canvas) //ha nem felelt meg a típus tesztnek, akkor null lesz az (entity as? Renderable) rész } -
lateinit → ha valamit csak később akarunk majd inicializálni
private lateinit var timer: AnimationTimer //innentől ki van kapcsolva a null safety-ség //ha inicializálás előtt akarjuk használni, akkor errort kapunk! -
platform type (String!) → Java-val való interakciókor jönnek létre
-
Java-bol Kotlin-ba híváskor Java nem ismeri a nullable és notnull dolgokat
- megjelenik egy checkNotNull
Funkcionális programozás¶
-
alapelvek
- függvények elsőrendű tagjai a nyelvnek (azaz nem csak osztály részeként lehet függvény)
- pure függvények → csak az inputjaik alapján visszaadnak valamit (mástól nem függenek)
- inkább val-okat használjuk → kevés olyan változónk van, aminek megváltozhat az értéke
- imperatív helyett dekleratívan programozunk
- nem a folyamatot írjuk le, hanem hogy mit akarunk megkapni
-
függvények rendezése
- pl package-eken belül
- megadhatjuk, hogy Java kódból milyen osztályból érhessük el ezeket
@file:JvmName("TextUtils") //ezzel az annotációval megadható, hogy milyen osztályba legyenek becsomagolva ezek a függvények (az egész file-t becsomagolja) package util val LOWERCASE_ALPHABET = "abcdefghijklmnopqrstuvxyz" fun isEmpty(str: String?): Boolean { return str == null || str.lenght == 0 } //random .java file: import util.TextUtils; class Main { public statis void main(String[] args) { TextUtils.isEmpty("is emptry?"); } } -
extensions → szép utility függvények
-
meglévő típus kibővítése új metódusokkal
fun String.lastChar(): Char { return this[this.length - 1] } fun main() { println("Steve".lastChar()) } -
fontos hibalehetőség: extension-nel nem nagyon megy a polimorfizmus!
abstract class Animal fun Animal.identify() { println("This is an animal") } class Cat: Animal() fun Cat.identify() { println("This is a cat!") } fun main() { val animal: Animal = Cat() animal.identify() // This is an animal-t fog kiírni! }- fordítási időben kellene eldönteni, hogy melyik függvény legyen meghívva, akkor azonban nem feltétlenül tudjuk (a polimorfizmusnak pont ez a lényege)
-