Obsah
Kotlin - základy
Úvod
Kotlin je moderný programovací jazyk. Vytvorila ho firma JetBrains. Vysokú podporu má od Google a preto je využitý v platforme Android. Je však natoľko univerzálny a má takú podporu knižníc, že je využitý i pre multiplatformové nasadenie pre iOS, web frontend (JavaScript), Linux, Windows a aj servery (Ktor), kde beží pod JVM (Java, napríklad Apache Tomcat).
Vyznačuje sa stručnosťou (oproti Java). Je možné v jednom projekte kombinovať Java aj Kotlin. Bezpečnosť voči null ukazateľom je vyriešená (null safety). Lambda funkcie výrzane uľahčujú písanie a stručnosť kódu. Coroutins zjednodušujú prácu s asynchronnými procesmi (vlákna) a preberanie odpovedí z nich.
Základné špecifikácie a príkazy
Označenie premenných
var : variable (dynamický obsah)
val : value (konštantná hodnota)
Typy premenných
Celé čísla
| Byte | -128..127, 8 bit |
| Short | -32768..32767, 16 bit |
| Int | -2147483648..2147483647, 32 bit |
| Long | -263 .. 263 - 1, 64 bit |
Desatinné čísla
| Float | +-1.4 * 10^−45 .. +-3.4 * 1038, presnosť: 7 čísel |
| Double | +-5.0 * 10^−324 .. +-1.7 * 10308, presnosť: 15 .. 16 čísel |
Ďalšie typy
| Char | 16 bit |
| Boolean | 8 bit |
| String |
Operátory
==, >, <, <=, >=, !=, !
Podmienky
if ()
if() else
if() else if()
when(var) {…} \\ when(val) {val → {…} else → {…}}
when() else
reťazenie podmienok
&&, ||
Cykly
for (i in m..n)
while ()
repeat(n) {}
it : aktuálny riadok cyklu
fun myFc() = sequence<Int> { for(i in m..n) { yield(i) // yield() vracia hodnotu, zväčša do .forEach{} volajúcej fc } }
Null safety
var myValue:<ValueType>? : povolenie null
anyCommand(myValue!!) : vypnutie kontroly
myValue?.let { anyCommand } : bezpečné volanie
anyCommand(myValue?.anyMethod ?: defaultValue) : bezpečné volanie s elvis operátorom
Polia
var myArray = arrayOf<ValueType>()
val myArray: Array<ValueType>(val1, … val_n)
var myList: List<ValueType> = listOf() … myList += newValue … myList -= selectedList
Konverzie
val myArray: Array<CharSequence> = myArrayList.toTypedArray() // ArrayLit to Array
Reťazce
časté funkcie:
- contains(), endsWith(), startsWith()
- toUpperCase(), toLowerCase()
- replace()
- trim()
- first(), last(), indexOf()
- substring(), compareTo()
- split(), joinToString()
- length
Matematické funkcie
import kotlin.math.*
- konštanty: PI, E
- min(), max()
- round(), ceil(), floor(), truncate()
- abs(), sign()
- sin(), cos(), tan(), acos(), asin(), atan()
- pow(), sqrt() : myDouble.pow(n)
- exp(), log(), log10(), log2()
- /, %
Objektové programovanie - OOP
class - Trieda:
- zapúzdrenie : skrytie atribútov a metód
- dedičnosť : od pôvodných tried
- polymorfizmus : prepísanie metód
Deklarácie
Deklarácia triedy
class MyClass { … }
Deklarácia metódy
[modifikatorPristupu] [menoMetody] ([parametre]) : [navratovyTyp]
- fun
Deklarácia vlastnosti
- var, val : základné
Vytvorenie inštancie
- automatocké vytvorenie koštruktora pri vytvorení inštancie
val myValue = MyClass()
Konštruktory
class MyClass(myValue: ValueType) { val myVal: ValueType init { this.myVal = myValue } }
class MyClass(val myValue: ValueType) { constructor() : this(defaultValue) }
Zapúzdrenie
- private val/var/fun : bez dedičnosti
- protected val/var/fun : v materskej triede
- open fun : v materskej triede
- call getter and setter from java: getPropertyName(), setPropertyName() - auto generate g/s in Kotlin
class MyClass(private var myValue) { // getters and setters fun getMyValue(): ValueType { // getter return myValue } fun setMyValue(myVal valueType) { // setter myValue = myVal } }
class MyClass(myValue: ValueType) { // private set var myValue = myValue private set }
class MyClass(myValue: ValueType) { // backing properties var myValue = myValue private set get() { return expressionResult } }
class MyClass(myValue: ValueType) { // set value var myValue = myValue [private] set(value) { foo = value } }
Dedičnosť
- open class MyOriginalClass { … }
- class MyNewClass: MyOriginalClass { … }
open calss MyParentClass(protected val myOirginalVale: ValueType) { … }
class MyChildClass(myOirginalVale: ValueType, private var myOtherValue: ValueType) : MyParentClass(myOirginalVale) { … init { this.myOtherValue = myOtherValue } }
Polymorfizmus
stejné meno metódy v dcérskej triede ako v materskej, ale iná funkcia
- override fun parentMethod() { … }
Companion objects - statika
class MyClass() { … companion object { val myValue = anyValue private var myLocalValue = anyValue fun myMethod(…): returnValueType { … } } }
Privátny konštruktor
statická trieda - objekt, bude dostupné všade aj bez inštancie
object MyObject { init { … } val/var/fun … }
Rozhranie
- samostaná deklarácia verejných metód
- nový interface sa genereje v IDE : New → Kotlin File/Class → Interface
- ak sú v rozhraní vytvorené aj telá metód, potom sa jedná o trait
- vicnásobná dedičnosť
rozhranie:
interface MyInterface { fun anyFunction() }
základná trieda:
class MyClass: MyInterface { override fun anyFunction() { … } }
volanie:
val myClass: MyInterface = MyClass()
viacnásobná dedičnosť
ďalšie rozhranie:
interface NextInterface { fun nextFunction() }
ďalšia trieda:
klik na žiarovku → Implement members
class NextClass: MyInterface, NextInterface { override fun anyFunction() { … } override fun nextFunction() { … } }
volanie:
val nextClass = NextClass()
volanie1:
val myClass: MyInterface = NextClass()
pretypovanie
- je možné na triedu i na rozhranie
val myClass: MyInterface = NextClass()
ok volanie:
myClass.anyFunction()
chybné volanie:
myClass.nextFunction()
ok volanie - pretypované:
(myClass as NextClass).nextFunction()
iné:
- if (myClass is MyClass) { … } - (myClass as MyClass).anyFunction()
Abstraktná trieda
- netvoria sa z nej inštancie (potomkovia)
- deklarujú sa hlavičky metód, nie telá, tie sa prepisujú u potomkov - akoby zlúčenie triedy a rozhrania
- abstract fun myMethod() → overrie fun myMethod() { … }
- abstract class MyClass(var anyValue: ValueType) { … }
Porovnanie objektov
- dajú sa porovnávať iba prvky, ktoré implementujú rozhranie Comparable, obsahujúce abstraktnú metódu compareTo(), kde návratová hodnota je -1, 0, 1
- override fun copareTo(other: MyClass): Int { return -1 or 0 or 1 }
- je možné vytvoriť triedu implementujúcu rozhranie Comparator pre predanie jej inštancií metóde sortWith()
- porovnanie je ďalej možné aj anonymnou funkciou a pomocou metódy sortBy()
Preťažovanie operátorov
- operator fun plus(myClass: MyClass): MyClass? { … }
Enum - výčtový typ
- prednastavené hodnoty
- nový enum sa genereje v IDE : New → Kotlin File/Class → Enum class
- enum class MyEnum { … }
- if (myStatus == MyEnum.myDefinitionValue) { … }
rozširenie enum o metódy:
enum class MyEnum { MyStatus1 { override fun toString(): String { return “anyString1” } }, MyStatus2 { override fun toString(): String { return “anyString2” } } }
prípadne:
enum class MyEnum(private val text: String) { // ! (private val text: String) je konštruktor ktorý vytvára v triede inštanciu MyStatus1(“anyString1”), MyStatus2(“anyString2”); override fun toString(): String { return text } }
Set - množina
- enum môže nadobúdať viacero stavov (napríklad práva používateľov)
private var myEnum: Set<MyEnum> init { myEnum(MyEnum.MyStatus1, MyEnum.MyStatus2) } myEnum += MyEnum.MyStatusN myEnum -= MyEnum.MyStatusN if (myEnum.contains(MyStatus1)) { … }
Konštanty
- súčasť triedy Any (všetky triedy sú jej potomkom…)
- sú konštantné vo svojej viditeľnosti kódu (príklad: kotlin.math → PI, E)
- zmena hodnoty je možná len v mieste jej definície
- definícia: const val MY_CONST_VALUE = anyValue
class MyClass { companion object { // static, use: myClass.MY_CONST_VALUE const val MY_CONST_VALUE = anyValue // const val je nastavená pri kompilácii, val môže meniť hodnotu napríklad z konštruktoru } }
Equals
- v základe porováva len referencie na inštancie
- generovanie equals() a hashCode(): rightClick na názov triedy → Generate → "equals() and hashCode()”, následne je použitľné porovnanie:
if (myClass_instance1 == myClass_instance2) { … }
Klonovanie
- objekt dedí z Any aj protected clone()
plytká kópia - shallow copy:
- atribúty sú nezávislé
- inštancie odkazujú v klone na pôvodné objekty
rozhranie Clonable:
class MyClass(val myVal: typeVal) Clonable { … } // Clonable je marker-interface - clone() je protected a definuje sa v triede: class MyClass(val myVal: typeVal) Clonable { public override fun clone(): Any { return super.clone() } }
hlboká kópia - deep copy:
- klonujú sa všetky vnútorné inštancie
public fun clone(): Any { val obj1 = super.clone() as Obj1 obj1.instX = obj1.instX.clone() as Obj2 return obj1 }
Datová trieda
- eliminuje zdĺhavosť tvorby equals(), hashCode(), toString(), componentN(), copy(), clone() a iné - generuje ich automaticky
- sú vhodné pre modely (dátové - uchovanie dát)
- primány konštruktor musí obsahovať minimálne jeden parameter (val alebo var)
data class Obj1(val val1: String, …)
- sekundárny konštruktor je v tele
data class Obj1(val val1: String, …) { constructor(val val1: String) : this(val val1: String, “other string parameter”, …) }
Linky:
Balíčky - packages
- určujú umiestnenie objektov v rámci projektu
- napríklad: LocalDate.now() == java.time.LocalDate.now()
Metóda s premenným počtom parametrov
- pomocou vararg príjma metóda premenlivý počet parametrov rovnakého typu
- prijaté parametre sú uložené v poli
- poľu môžu predchádzať iné parametre
fun fun1(…, Ivararg vars1: ValType): ValType { for (item in vars1) { … } return result }
Preťažovanie a prekrývanie metód
Preťažovanie metód
- stejný názov, ale iné parametre
- pri preťažení konštruktorov za zátvorku konštruktora vložíme: : this( …iné parametre… )
- volanie konštruktora predka: : super(parametre)
Prekrývanie metód
- ak je v rodičovi metóda označená open, potom v potomkovi ju prepíšeme označením override
- metóda predka sa v potomkovi volá: super.metoda()
Vnorené triedy
class Obj1 { class Obj2 { } }
- - prístup: Obj1.Obj2
Východzie parametre
- nastaví sa, ak nie je uvedený (podobne ako v PHP)
fun fun1(par1: ValType, par2: ValType = anyValue) { ... }
Parametre s menom
- volať funkciu je možn aj s menom parametru, čo je vhodné ak sa zmení poradie v definícii
funX(par2 = anyValue, par1 = anyValue)
Jednovýrazové funkcie
fun fun1(): ValType = anyValue + anyValue // príklad pre sčítanie
Pomôcky
Dátum a Čas
Odporúča sa použiť LcalDateTime z Java 8, nie Date, alebo Calendar, alebo Joda-Time
získanie:
import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime import java.time.Month
aplikovanie:
val datumCas = LocalDateTime.of(2016, Month.APRIL, 15, 3, 15) // dátum a čas val datum = LocalDate.of(2016, Month.APRIL, 15) // len dátum val cas = LocalTime.of(3, 15, 10) // len čas val datumCas = LocalDateTime.now() val datum = LocalDate.now() val cas = LocalTime.now()
formátovanie:
import java.time.format.DateTimeFormatter import java.time.format.FormatStyle
aplikovanie:
val dateTime = LocalDateTime.now() println(dateTime.format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM))) println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL))) println(dateTime.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT))) println(dateTime.format(DateTimeFormatter.ofPattern("d.M.y H:m:ss")))
prevody z LocalDateTime:
https://www.itnetwork.cz/kotlin/oop/datum-a-cas-v-kotlin-uprava-a-intervaly
toLocalDate() toLocalTime()
prevody na LocalDateTime:
val zacatek = LocalDate.of(1939, 9, 1) val datumCas = zacatek.atStartOfDay() val datumCas2 = zacatek.atTime(0, 0)
úpravy hodnôt:
minusDays(), minusHours(), minusMinutes(), minusMonths(), minusNanos(), minusSeconds(), minusWeeks(), minusYears() plusDays(), plusHours(), plusMinutes(), plusMonths(), plusNanos(), plusSeconds(), plusWeeks(), plusYears()
Period a Duration:
import java.time.Period
práca s intervalom - minus(), plus() ⇒ Period a Duration Duraton je len interval bez súvisu na kalendár Pariod akceptuje prechody na letný/zimný čas
ChronoUnit:
import java.time.temporal.ChronoUnit
pre prácu s intervalom (pre Duration)
Betwen:
získanie intervalu medzi dvoma dátumami
porovnanie:
compareTo(), isAfter(), isBefore(), isEqual(), isLeapYear(), isSupported(ChronoUnit.X)
ostatné:
Instant : nanosekundy od 1.1.1970 - Instant.now() #thisDteIsBeginOfLinuxEpoch ZoneId : špecifikácia zóny - ZonedDateTime.now(ZoneId.of("America/New_York")) .ofEpochSecond() : linux timestamp = sekundy od 1.1.1970 : LocalDate.ofEpochSecond() toEpochSecond(), toEpochDay() : prevod na sekundy
Systém
Melanie času behu
po ukončení bloku measureTimeMillis {} je vrátený čas jeho trvania v milisekundách:
val runningTime = measureTimeMillis { dataOperation() } println(runningTime)
Linky
- kotlin playground: https://play.kotlinlang.org/
- java playground: https://dev.java/playground/
- kotlinlang.org : kurz Kotlin, JetBrains
- developer.android : všetko o Kotline
- w3schools : Kotlin tutorial
- https://www.itnetwork.cz/kotlin všetky kurzy
Iné vzdelávacie portály
Užitočné linky
- Ktor - framework pre : server, client, multiplatform : https://ktor.io/docs/welcome.htm
- info o Ktor pre Android: https://medium.com/@stefanoq21/ktor-my-favorite-http-client-for-android-3955c2c2cd7c
- Kotlin Multiplatform - get started: https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html
Vzdelávacie linky
Tu sú uvedené linky na Kotlin portfolio vzdelávánie od JetBrains a Google.
Kotlin Docs - Základy (kotlinlang.org)
Kotlin Multiplatform - Začíname s KMP (kotlinlang.org)
Compose Multiplatform - Tvorba UI (jetbrains.com)
Ktor - Dokumentácia Ktor (ktor.io)
Android developers developers (developer.android.com)
