És hasonlókat is vonhat a Java-val 20215. február 18. perc52https: //d2xzmw6cctk25h.cloudfront.net/post/2552/og_image/c775b5c31db1dfd507bc5dfe763ec072.png
Kotlin érdekes alaptípusokkal rendelkezik, amelyek némileg kapcsolódnak a Java-hoz. Ez az egység, semmi, semmi. Lássuk, melyek ezek az osztályok, miben különböznek (hasonló nevek ellenére), és hasonlítsuk össze őket Java-társaikkal. Beszéljünk még egy kicsit a nullról Kotlinban, mert ezek a témák összefüggenek.
Mértékegység
Az egység egyenértékű a Java-ban érvénytelennel. Ebben a kifejezésben a return típus elhagyható, ha a függvény nem ad semmit. Alapértelmezés szerint az Unit ott lesz:
fun knockKnock () {println ("Ki van ott?")}
Kotlinban kétféle módon lehet deklarálni egy függvényt: a módszer törzsében (göndör zárójelben) vagy kifejezésként (az egyenlőségjel használatával). Így átírhatja függvényünket, és megadhatja a visszatérési értéket:
fun knockKnock (): Unit = println ("Ki van ott?")
A szokásos Kotlin könyvtárban az egységet olyan objektumként definiálják, amely örököl mindeniktől, és egyetlen metódust tartalmaz, amely felülbírálja a
public object Unit {override fun toString () = "kotlin.Unit"}
Ügyeljen az objektum kulcsszavára. Ez azt jelenti, hogy az Unit egyedülálló. Az egység nem ad semmit, és a toString metódus mindig a „kotlin.Unit” értéket adja vissza. Java-kódra fordítva az Unit mindig érvénytelen lesz.
Érdekes, hogy a Java-nak megvan a maga Void osztálya, amely meglehetősen gyenge, de mégis korrelál a voiddal és nem példázható. Ez egy pusztán haszonelvű osztály, amelyre szükség van a Java elmélkedéséhez és általános ismereteihez.
Semmi
Semmi sem sokkal érdekesebb. Semmi sem olyan osztály, amely Kotlin bármely osztályától örököl, még a végső módosítóval rendelkező osztálytól is. Semmit azonban nem lehet létrehozni – van privát konstruktora. A kódban ezt így deklarálják:
nyilvános osztály Semmi magánépítő ()
Mindezek ellenére a Semmi osztály elég hasznos. Mivel lehetetlen átadni vagy visszaküldeni a Semmi típust, leírja egy “funkció, amely soha nem ad vissza semmit” eredményét. Példaként szolgálhat egy olyan funkció, amely kivételt vet, vagy amelyben egy végtelen ciklust indítanak: mindkét esetben soha nem ad vissza értéket. Az alkalmazásokban, függetlenül attól, hogy milyen adattípust ad vissza a függvény, előfordulhat, hogy soha nem ad vissza adatokat, mert hiba történt, vagy a számítások végtelenségig késnek. Ebben az esetben van értelme a Semmit használni.
Lássuk, hol használják ezt Kotlinban. Íme egy példa: a TODO () függvény, amelyet gyakran használnak csonkként az automatikusan létrehozott módszerekben.
public inline fun TODO (): Semmi = dobás NotImplementedError ()
A kód automatikus létrehozásakor a következő képet láthatja:
felülírja a szórakoztató getData (szó: karakterlánc): Lista {TODO ("nincs megvalósítva")}
Bár a visszatérési érték List , a Semmit nem adjuk meg. Pontosan azért, mert semmi sem öröklődik minden osztályból:
fun doSomething (): Valami = TODO ()
A kód nagyon jól összeáll, mert Semmi sem öröklik a Valamitől. De az alkalmazás azonnal összeomlik a NotImplementedError programmal, ha meghívja a doSomething metódust.
Érdekes módon nem írhat ilyesmit a Java-ra: a kód egyszerűen nem fordul össze, mert a Void nem örökli a String-et:
statikus Void todo () {dobjon új RuntimeException-t ("Nincs megvalósítva"); } Karakterlánc myMethod () {return todo (); }
Egy másik példa a végrehajtásra vonatkozhat, például adatkérés adatbázisból vagy távoli szerverről. Ha hiba lép fel, akkor az adatok helyett null értéket adhat vissza. És ez teljesen normális, nincs adat:
fun getData (): Adatok? = ...
Mi van, ha egy kicsit több információt szeretne, nem csak nullát? Például megtudhatja a hiba típusát. Itt nem jön semmi a megmentésre:
fun getData (onError: (SomeError) -> Semmi): Data = ...
Így nézhet ki a kódban:
val data = getData () {err -> mikor (err) {értéke InvalidStatement -> dobás Kivétel (err.parseError) NoSuchData -> ...}} return Data () // sikeres szkript}
Javítsuk ki:
// Összeállítás általában fun funOne (): Unit {while (true) {}} fun funTwo (): Semmi {while (true) {}} // Ok fun funThree (): Unit {println ("hi")} / / Nem jó szórakozás funFour (): Semmi {println ("szia")}
Bármi
Bármely osztály a hierarchia tetején áll – Kotlinban az összes osztály örököl Anyitól. Bármelyik analóg az Java objektummal, de kevesebb módszerrel:
nyilvános nyílt osztály Bármely {public open operator fun egyenlő (egyéb: Bármi?): Boole-i nyilvános open fun hashCode (): Int nyilvános open fun toString (): String}
Tizenegy módszer létezik a java.lang.Object fájlban, és öt közülük többszálas kezeléssel foglalkozik. A kisebb számú módszer ellenére Java-kódra történő fordításkor bármelyik osztálynak hiányoznak – itt nyugodt lehet.
Nulla
Kotlinban a null semmisséges típusokat alkothat (“nullable” -nek ejtve). Jelzéssel jelzik? a típus végén. Például String? String + null típusú. Vagyis az érték lehet string, vagy lehet null. A Java-ban ilyen kiegészítésekre nincs szükség – minden objektum null lehet, és ez a Kotlin nyelv egyik előnyéhez vezet a Java-val szemben – a null biztonsághoz.
A Java-ban mindig meghívhatja az objektum metódusait, és csak a program munkája során tudja meg, hogy az objektuma null. Ezután az alkalmazás összeomlik egy NPE (NullPointerException) hibával. Ez általában a Java leggyakoribb hibája.
Kotlinban a kódod egyszerűen nem fordul össze, ha olyan objektumokat hívsz meg, amelyek nullák lehetnek, vagyis? Signal vannak jelölve. Kötelező null ellenőrzés szükséges. Ha a típus nincs a végén? – garantálja, hogy az objektum soha nem lehet null. Ez segít azonosítani az NPE-vel kapcsolatos esetleges hibákat, még a kódírás szakaszában is – és nem akkor, amikor az alkalmazás már fut, vagy a boltban van, mint a Java esetében.
A Kotlin létrehozásakor a fejlesztők igyekeztek a lehető legbiztonságosabbá tenni. Írjuk a következő kódot:
var notNullable: String = "" notNullable = null // Fordítási hiba
Mit kapunk ennek eredményeként? Összeállítási hiba. A null eltárolásához egy változóban megfelelően deklarálnia kell:
var nullable: Karakterlánc? = ""
Ha egy nullázhatatlan változó értékét próbálja hozzárendelni egy nem nullázhatatlan változóhoz, a fordító megakadályozza a következő kód fordítását:
nontNullable = nullable // Fordítási hiba
Emellett nem fogunk tudni egy ilyen változóban tárolt objektum metódusait meghívni:
val hossz = nullable.length // Fordítási hiba
Ha olyan nullázható változóhoz kíván értéket rendelni, amely nem támogatja a null értéket, először ellenőriznie kell, hogy a nullable tartalmaz-e null értéket:
if (nullable! = null) {length = nullable.length // OK nonNullable = nullable // OK}
Ezt követően az ellenőrzés körében a nullable változót a fordító nem nullable típusnak tekinti. Biztonságosan hozzáférhet egy változóban tárolt objektumhoz.
A NullPointerException elleni védelem fordítói szinten valósul meg. Ez nemcsak a változókra vonatkozik, hanem a kifejezésekre és a függvényhívásokra is. A fordító nem engedi átadni egy nullázható típusokat támogató változó értékét egy függvénynek, ha a funkciódefinícióban csak nonNull paraméterek vannak deklarálva. És ez nem teszi lehetővé olyan változó hozzárendelését, amely nem támogatja a null értéket, azt az értéket, amely egy olyan kifejezésből származik, amely null értéket adhat vissza.
var name: String = "Ivan" var fullName: Karakterlánc? = "" fun checkStirng (s: String): Karakterlánc? {...} checkString (fullName) // Fordítási hiba neve = checkString (név) // Fordítási hiba
Lássunk egy másik példát a Java-ból:
osztály Személy {Preson (String keresztnév, String második név, int kor) {...}} Személy személy = új Személy (null, null, 29); person.getFirstName (). hossz ()
A kód végrehajtásakor a program hibával összeomlik. És csak az előadás során tudunk meg róla. Természetesen ez a kód egyszerűsített változata, ahol a hiba azonnal látható. De egy valódi programban nehéz megtalálni az ilyen hibákat. Mit kínál Kotlin:
osztály Személy (keresztnév: Karakterlánc, másodikNév: Karakterlánc, életkor: Int) val személy = Személy (null, null, 29) // fordítási hiba
Kotlinban, annak semmissé váló típusaival, ez a kód egyszerűen nem fog fordítani. A konstruktorában található Person osztály olyan típusú paraméterekkel rendelkezik, amelyek nem támogatják a null értéket. Ezért a fordító nyomon tudja követni ezt, és nem engedi, hogy ilyen kódot gyűjtsön. Csak akkor, ha kifejezetten és meghatározott célból jelzi, hogy a paraméterek nullák lehetnek, a kód összeáll és az alkalmazás elindul. De akkor az NPE-vel kapcsolatos minden felelősség Önre hárul:
osztály Személy (keresztnév: Karakterlánc?, másodikNév: Karakterlánc?, kor: Int?) val személy = Személy (null, null, null) // Minden rendben van!
A Java nyelvi szinten nem támogatja a null biztonságot, ezért ott megjegyzéseket kell használnia. Ez nem csak extra kódsorokat ad hozzá, de nem is garantálja a biztonságot – a kód jól épít, és elfogadja a nullat ott is, ahol nem kellene. A kommentár csak a problémás területeket emeli ki. Kotlinban az ilyen kód egyszerűen nem áll össze.
Minden alkalommal, amikor nullát írunk be, a „ha (s! = Null) …” nem tűnik vonzónak. Kotlin pedig kényelmesebb eszközöket kínál a nullázhatatlan típusokkal való munkavégzéshez. Beszéljünk róluk.
Biztonságos híváskezelő
Az első ilyen eszköz a Secure Call Operator. Úgy néz ki, mint egy kérdőjel, amelyet egy pont követ:
val név: Húr? = "John" val nameLength: Int? = név? .hossz
A metódus meghívása előtt ellenőrzi a nullát. Ha a változó értéke null, akkor kivétel helyett ez a kifejezés egyszerűen nullát ad vissza. Vagyis, ha a név == null, akkor a nameLength értéke == null vagy a nameLength == 4 lesz . Nagyon kényelmes és gyors ellenőrzés, amelyet gyakran használnak kódban (alkalmazásunkban ezt az operátort is használni fogjuk).
“Elvis” kezelő
Egy másik kényelmes kezelő a biztonságos munkavégzéshez. Elvis betűje:? (Kérdőjel, amelyet kettőspont követ). Ha felhasználja fantáziáját és szögből nézi a felvételt, hasonlóságokat találhat Presley képével:
val nameLength: Int = név? .hossz ?: 1
A működés elve a következő: ha a bal oldalon lévő kifejezés nem tér vissza nullára, akkor megkapjuk a név hosszát; ha null, akkor az operátor jobb oldalán lévő kifejezés értéke visszatér. Ez megkönnyíti a null érték ellenőrzését és az alapértelmezett érték visszaadását. A fenti példa alapján, ha a név == null, akkor a nameLength értéke == 1 vagy a nameLength == 4 lesz.
Egyelőre ennyi, maradjunk kapcsolatban! Ez az első cikk az “Oktatási program” sorozatból. A következő bejegyzések gyűjteményekről, kiterjesztésekről, többszörös öröklésről, lezárt osztályokról és még sok minden másról szólnak – kövesse a blogot!