1. Niyə ?. ve ?: lazimdir ve niyə tek if kifayet etmir
Siz yeni null haqqinda oyrenende, adeten ilk reaksiya bele olur: “OK, her yerde yazacam: if (x != null)”. Bu normal baslangicdir, amma cox tez agri hiss edersiniz: ic-ice if-ler boyuyur, mentiq kodun icine yayilir, proqrami oxumaq ise labirint kecmeye benzemeye baslayir (ve sonda sizi yenə minotavr gozləyə biler).
Kotlin daha ifadeli konstruksiyalar teklif edir: qisa operatorlar ki, null-un emalini ifadənin bir hissesine cevirir. Bu vacibdir, cunku bir cox tapsiriq “emel et ya da etme” deyil, “eger varsa deyeri al, yoxdursa ehtiyat varianti istifade et” tipindedir. Mehz bunun ucun ?. ve ?: movcuddur.
Menzerəni yadda saxlamaq ucun, budur mini-cədvəl:
| Operator | Necə oxunur | Ideya | Nə qaytarir |
|---|---|---|---|
|
“eger null deyilse — et, yoxsa null qaytar” | tehlükəsiz giris | cox vaxt T? |
|
“eger sol teref null-dursa — sag terefden gotur” | defolt deyer / ehtiyat davranis | tez-tez nullable-ni aradan qaldirir |
|
“men and icirem ki, burada null deyil” | meqsedli (zorla) giris | T, amma dusme riski var |
Davaminda her aləti sakit-sekilde ve numunelerle izah edeceyik.
2. Safe call ?.: dusmeden tehlükəsiz giris
Operator ?. adeten ona gore sevilir ki, kodu hem qisa, hem de tehlükəsiz edir. Amma esas meselen — davranisi aciq etməsidir: siz birbasa kod setrinde gosterirsiniz ki, deyer olmaya da biler, ve siz bu senariye hazirsiniz. Bu, tehlükəsizlik kemeri kimi bir seydir: qezani planlamirsiniz, amma insan ozunu daha rahat hiss edir.
?. xasselerde: risk olmadan .length
En sade numune — setrin uzunlugudur. Eger setir nullable-dirsa, birbasa giris qadağandir:
fun main() {
val nickname: String? = null
println(nickname.length) // bele olmaz: nickname null ola biler
val len: Int? = nickname?.length
println(len) // null
}
Burada bir seyi mutleq gormek lazimdir: netice nickname?.length tip olaraq Int? olur, cunku emeliyyat “icra olunmaya” biler (solda null olarsa, uzunlugu hesablayacaq hec ne yoxdur).
Bu cox mentiqlidir: safe call havadan uzunluq “uydurmur”. O, duzunu deyir: “Ya uzunlugu qaytaracam, ya da null”.
?. metodlarda: uppercase() ucun tehlükəsiz cagiris
Eyni prinsip metodlarda da kecerlidir:
fun main() {
val nickname: String? = "neo"
val upper: String? = nickname?.uppercase()
println(upper) // NEO
}
Eger nickname null olsa, onda upper de null olacaq ve proqram dusmeyecek.
Safe call zəncirləri: “?.-den domino”
Adeten ?. bir defe deyil, zəncir kimi istifade olunur: “setri gotur → bosluqlari kes → boyuk herflere cevir → uzunlugu gotur”. Ve her addimda deyer null ola biler (eger girisde null idise).
fun main() {
val raw: String? = " Kotlin "
val len: Int? = raw
?.trim()
?.uppercase()
?.length
println(len) // 6
}
Oxunusu rahatdir: deyer olduqca davam edirik; deyer olmayan kimi butun zəncir null-a cevrilir.
Mini-sxem: ?. nə edir
Möhkəmləndirmək ucun, ?.-in isini kicik blok-sxem kimi tesəvvur edək:
flowchart TD
A["Deyer var: x: T?"] --> B{ x == null? }
B -->|he| C["Netice = null"]
B -->|yox| D["x.member / x.func() icra edirik"]
D --> E["Netice = deyer"]
Beli, operator iki simvoldan ibaretdir, amma arxasinda tam konkret mentiq durur.
3. ?: operatoru
Operator ?: (Elvis, cunku Elvis Presli-nin sac duzumunu xatirladir) imkan verir ki, null-u normal bir deyerle (ya da normal bir emelle) evez edəsiniz.
Elvis “defolt deyer” kimi
En cox rast gelinen forma:
fun main() {
val nickname: String? = null
val len: Int = nickname?.length ?: 0
println(len) // 0
}
Tipə diqqet edin: solda nickname?.length Int? verir, amma Elvis 0 qoyduguna gore netice — adi Int-dir.
Bu, esas patterlerden biridir: ?. tez-tez “nullable yaradir”, ?: ise tez-tez “nullable-ni goturur”.
Elvis ve setr mesaji: konsolda normal UX
Konsol proqramlarimizda yalniz “dusmemek” deyil, hem de istifadeci ile insani sekilde danismaq vacibdir.
fun main() {
val nickname: String? = null
val label: String = nickname?.uppercase() ?: "ANONYMOUS"
println("Hello, $label!") // Hello, ANONYMOUS!
}
Deyer varsa — gozel formatlayiriq. Yoxdursa — ehtiyat mətni gosteririk.
Elvis erkən cixis kimi
Bezen null “0 qoyaq” demek deyil, “demeli, daha davam etmek olmaz” demekdir. Onda defolt deyer yerine funksiyadan erkən cixir edirik.
Kotlin return-u Elvis ile birlikde istifade etmeye icaze verir:
fun parsePositiveInt(text: String): Int? {
val x: Int = text.toIntOrNull() ?: return null
if (x <= 0) return null
return x
}
fun main() {
println(parsePositiveInt("42")) // 42
println(parsePositiveInt("oops")) // null
println(parsePositiveInt("-5")) // null
}
Ideya beledir: problemi elə baslangicda “lokallasdiririq”. Parse olunmadisa — null qaytaririq ve ic-ice if-lər qurmuruq.
4. Mene inan, qardas
Operator !! kompayleri “susdurmagin” sade yolu kimi gorunur: o, T?-ni T-ye cevirir. Amma bunu cox birbasa edir: eger deyer null cixsa, proqram icra zamani dusur (adeten bu KotlinNullPointerException olur).
Vacib fikir: !! kodunuzu daha tehlükəsiz etmir. O, kodunuzu kompilyasiya olunan edir, tehlükəsizliyi ise sizin eminliyinizin uzerine yukleyir.
Numune: kompilyasiya olunur, amma dusur
fun main() {
val nickname: String? = null
val len: Int = nickname!!.length
println(len) // proqram bura catmayacaq
}
Bu kodu isletsəniz, proqramin dusmesini goreceksiniz. Yəni !! “null-un emali” deyil, bu “men null olmadigina zemanet verirem” demekdir.
!! hansi hallarda umumen mentiqli olur
Fanatizm olmadan: !!-i “yanqin olsa sindir” tipli tecili duymə kimi qebul etmek olar. Bezen siz tam eminsiniz ki, deyer hec cur null ola bilmez, ve eger birdən null olarsa — bu dogrudan da elə bir bagdir ki, onu derhal askar etmek daha yaxsidir.
Amma praktika gosterir ki, baslangic seviyyeli developer !! qoyursa, bu cox vaxt bele demekdir: “Men null-u duzgun emal etmeyi basa dusmedim”. Ona gore de baz qayda sadedir: evvela ?., ?: ve ya if yoxlamasi ile hell axtaririq, yalniz sonra (nadir hallarda) !!-e baxiriq.
4. Istifadeci anketi: opsional sahələr ve null-un emali
Gelin eyni konsol tetbiqini inkisaf etdirmeye davam edək: sade bir “istifadeci anketi”. Evvel setrleri oxuyur, trim() edirdik, ededleri toIntOrNull() ile parse edirdik. Indi opsional sahələr (buraxila bilən) elave edək ve ?., ?: ile səliqəli patterlərden istifade edək.
Mənanı razilashdiraq: bos setir vs null
Cox yaygin qarisiqliq: istifadeci Enter basdi ve bos setir "" daxil etdi. Bu null deyil. Amma bizim mentiq ucun “hec ne daxil etmedi” cox vaxt “deyer yoxdur” demekdir. Ona gore biz ozumuz bos setri null-a cevira bilerik.
Kicik komezci funksiya yazaq:
fun emptyToNull(text: String): String? {
val trimmed = text.trim()
return if (trimmed.isEmpty()) null else trimmed
}
Nikneymi String? kimi oxuyuruq ve cixisi formatlayiriq
fun emptyToNull(text: String): String? {
val trimmed = text.trim()
return if (trimmed.isEmpty()) null else trimmed
}
fun main() {
println("Nikneyminizi daxil edin (bos ola biler):")
val nicknameInput = readln()
val nickname: String? = emptyToNull(nicknameInput)
val label = nickname?.uppercase() ?: "ANONYMOUS"
println("Sizin etiket: $label") // eger bosdursa: "Sizin etiket: ANONYMOUS"
}
Burada derhal iki alət var: ?.uppercase() ve ?: "ANONYMOUS".
Yas: toIntOrNull() Int? verir, ve bu normaldir
Indi yas sorusacagiq, amma onu mecburi etmeyeceyik (meselen, istifadeci paylasmaq istemir).
fun emptyToNull(text: String): String? {
val trimmed = text.trim()
return if (trimmed.isEmpty()) null else trimmed
}
fun main() {
println("Yasinizi daxil edin (bos ola biler):")
val ageText: String? = emptyToNull(readln())
val age: Int? = ageText?.toIntOrNull()
println("age = $age") // meselen: age = 25 veya age = null
}
Cox vacib meqam: biz ageText.toIntOrNull() yaza bilmerik, cunku ageText nullable-dir. Ona gore ya if, ya da ?.. Biz ?. secdik.
Gozel cixis: “null” deyil, normal ifade qururuq
Indi istifadeci ucun normal mesaj edək:
fun emptyToNull(text: String): String? {
val trimmed = text.trim()
return if (trimmed.isEmpty()) null else trimmed
}
fun main() {
println("Yasinizi daxil edin (bos ola biler):")
val ageText: String? = emptyToNull(readln())
val age: Int? = ageText?.toIntOrNull()
val ageLabel: String = age?.toString() ?: "gosterilmeyib"
println("Yas: $ageLabel") // meselen: "Yas: gosterilmeyib"
}
Burada daha bir “korpü” qurmusuq: age — Int?-dir, Elvis ise bunu metne cevirir, ve onu utanmadan cap etmek olur.
“null-u derhal emal et” patterni: ic-iceliyi azaldiriq
Tesəvvur edək ki, “teqribi dogum ilini” hesablamaq isteyirik (serti olaraq 2026 - age). Vacibdir: 2026 burada sadəcə numune ucun secilmis ildir. Yas yoxdursa, hesablamaq menasizdir.
Netice kimi setir qaytaran funksiya yazaq:
fun estimateBirthYear(ageText: String?): String {
val age: Int = ageText?.toIntOrNull() ?: return "Dogum ili: melum deyil"
val year = 2026 - age
return "Dogum ili teqriben: $year"
}
fun main() {
println(estimateBirthYear("20")) // Dogum ili teqriben: 2006
println(estimateBirthYear(null)) // Dogum ili: melum deyil
println(estimateBirthYear("abc")) // Dogum ili: melum deyil
}
Burada Elvis defolt deyerle deyil, defolt davranisla istifade olunur: erkən qaytaris.
Anketin tam yigimi
Anketin sadeleşdirilmis versiyasini yigiriq: ad mecburidir, nikneym ve yas — yox.
fun emptyToNull(text: String): String? {
val trimmed = text.trim()
return if (trimmed.isEmpty()) null else trimmed
}
fun main() {
println("Ad (mecburi):")
val name: String = readln().trim()
println("Nikneym (bos ola biler):")
val nickname: String? = emptyToNull(readln())
println("Yas (bos ola biler):")
val ageText: String? = emptyToNull(readln())
val age: Int? = ageText?.toIntOrNull()
val shownNickname = nickname?.uppercase() ?: "ANONYMOUS"
val shownAge = age?.toString() ?: "gosterilmeyib"
println("Profil: $name / $shownNickname / yas: $shownAge")
// Numune: "Profil: Alice / ANONYMOUS / yas: gosterilmeyib"
}
Burada bizde səliqəli bir “emal borusu” alinir:
readln() → trim() → (mumkun olsa) emptyToNull() → (mumkun olsa) ?.toIntOrNull() → ?: ile formatlama.
Bu, nullable ile islemeyin normal stilidir: ne artiq derecede, ne de vecine almadan.
5. ?., ?: ve !! ile islerken tipik sehvler
Sehv №1: ?.-in defolt deyer qoydugunu gozlemek.
Baslangicda bezi insanlar safe call-u bele oxuyur: “eger null-dursa, nese oz-ozune duzelecek”. Xeyr: ?. sadəcə onu temin edir ki, property/metoda muraciətde proqram dusmesin. Eger solda null varsa, ifadənin neticesi de null olacaq. Eger sizə defolt lazimdirsa, bu artiq Elvis ?:-in isidir, ve defolt menali olmalidir, “tekce kompilyasiya olsun” ucun yox.
Sehv №2: ?. zənciri uzanir ve oxunmaz olur.
Texniki olaraq ard-arda bes-alti safe call yazmaq olar ve o, isleyer. Amma insan beyni kompayler deyil: uzun zəncirləri yadda saxlamaq cetindir, xususen de sonda ?: de varsa. Bele hallarda araliq val-lar yaratmaq ve onlara aydin adlar vermek daha yaxsidir, ki, kod addim-addim oxunsun, sehr kimi yox.
Sehv №3: menasiz sekilde ?: 0 ve ya ?: "" istifade edib problemi gizletmek.
Elvis cox cazibedardir: ?: 0 qoydun — ve her sey “isleyir”. Amma bezen bu, daxil etme xetasini gizledir veya mentiqi pozur. Meselen, yas 0 riyaziyyatda duzgun ola biler, amma anket ucun bu daha cox qeribe goruner. Daha yaxsi defoltlar secmekdir: predmet saheniz ucun menasi olanlari: “gosterilmeyib”, “melum deyil”, “—”, ve ya erkən return, eger deyersiz davam etmek menasizdirse.
Sehv №4: kompaylerin butun xetalarini !! ile “mualice etmek”.
!! dogrudan da kompaylerin mesajini tez “duzeldir”, cunku T?-ni T-ye cevirir. Amma bunun bedeli — runtime-da dusme riskidir ve ustelik cox vaxt gozlemediyiniz yerde (xususen de deyer daxil etməden gelirse). Sizin merhelenizde !!-i universal “cekic” kimi yox, null olanda dusmenin bilerekden secilmis kontrakt oldugu nadir hallar ucun alət kimi qebul etmek daha duzgundur.
Sehv №5: null ile bos setri qarishdirmaq ve bunun ucbatindan ?. ile ?:-i qeribe sekilde birlesdirmek.
Eger “istifadeci hec ne daxil etmedi” ne demekdir razilashdirmamisinizsa, surprizlerle qarsilasacaqsiniz. Bos setir "" — deyer demekdir ve ?. ona hec aid deyil (o, null deyil). Ona gore tez-tez daxil etmeyi aciq sekilde normallasdirmaq faydalidir: “trim()-dan sonra bosdursa” halini null-a cevirmek. Onda ?. ve ?: tam olaraq gozlediyiniz kimi isleyir, ve proqram proqnozlasdirila bilən olur.
GO TO FULL VERSION