Profinit Academy kombinuje výhody tradičního školení s tím nejlepším z e-learningu. Jedná se o kombinaci sledování školicích videí, samostudia z interních materiálů a praktických cvičení a konzultací s vedoucím. Akademií v Profinitu máme již 9, přičemž každá se zaměřuje na určitou skupinou technologií (např. Big Data, AWS atd.), a nedávno byl do tohoto seznamu přidán i Kotlin.
Kotlin akademie je ucelený soubor znalostí, který studenta provede stěžejními oblastmi jazyka Kotlin. Akademie je určena pro všechny úrovně znalostí. Ocení ji především juniorní kolegové, kteří s Kotlinem teprve začínají. Absolvent získá dostatečně kvalitní znalosti, které mu umožní plnohodnotně se zapojit do projektu psaného v Kotlinu.
Akademie je strukturovaná do několika oblastí dle obtížnosti. Jednotlivé kapitoly obsahují přehled témat, která se budou probírat. Témata jsou postavena na oficiální dokumentaci Kotlinu, doplněná o osobní poznatky či doporučení. U složitějších témat je k dispozici více odkazů nahlížejících na problematiku z různých úhlů pohledu. Na konci většiny oblastí je odkaz do Kotlin Koans, kde si účastníci mohou vyzkoušet nově nabyté znalosti na sérii jednoduchých příkladů.
V následujících odstavcích si přiblížíme několik klíčových konceptů jazyka Kotlin a jeho srovnání s jazykem Java, abyste měli lepší představu o tom, jak tento jazyk funguje a jak může posílit vaši vývojářskou dráhu.
Co se skrývá pod pokličkou jazyka Kotlin
Jak mnozí jistě víte, Kotlin se kompiluje do bytecode a běží nad jvm, stejně jako jazyk Java. Vývojáři v Javě mají povědomí o tom, jak jsou dané operace náročné a co se na pozadí děje. U Kotlinu tomu tak být na první pohled nemusí. Pojďme se podívat, jak některé konstrukty Kotlinu vypadají, když se přeloží do Javy.
Intellij IDEA nabízí možnost dekompilace z Kotlinu do Javy pomocí nabídky v menu:
Tools -> Kotlin -> Show Kotlin bytecode -> Decompile
Static function
Kotlin upustil od modifikátoru static, který známe z Javy. Oproti tomu nabízí jiné možnosti, jak pracovat s proměnnými a funkcemi bez vytváření instancí. Jedna z možností je pomocí companion objektu.
class Foo { companion object { fun debug(message: String) { print("Received: $message") } } }
Při použití v Kotlinu se to chová dle očekávání, k metodě debug lze přistoupit přes volání Foo.debug(). V Javě už to tak hezké není, a pokud bychom opravdu potřebovali volat tuto metodu v Javě, museli bychom k funkci debug přistoupit přes Foo.Companion.debug(), viz výsledek níže po dekompilaci z Kotlinu do Javy.
public class Foo { public static final Foo.Companion Companion = new Foo.Companion(null); public static final class Companion { public final void debug(@NotNull String message) { Intrinsics.checkNotNullParameter(message, "message"); String var2 = "Received: " + message; boolean var3 = false; System.out.print(var2); } private Companion() { } public Companion(DefaultConstructorMarker $constructor_marker) { this(); } } }
Řešením optimálního volání z Javy je přidání anotace @JvmStatic. Ta v Javě vygeneruje statickou metodu, která se následně použije jako Foo.debug().
public final class Foo { public static final Foo.Companion Companion = new Foo.Companion(null); @JvmStatic public static final void debug(@NotNull String message) { Companion.debug(message); } }
V izolovaném světě Kotlinu toto řešit nemusíte. Pokud by se ale mohl váš kód psaný v Kotlinu použít při volání v Javě, je vhodné mít podobné anotace na paměti.
When
Funkce when je v Kotlinu velmi používaná, ale ne každý ví, jak se doopravdy chová. Dokážete si tipnout, co by se vypsalo do konzole, pokud bychom provolali následující funkci s argumentem 15?
fun printPrimes(num: Int) { when { num % 5 == 0 -> print("Divisible by 5") num % 3 == 0 -> print("Divisible by 3") num % 2 == 0 -> print("Divisible by 2") } }
Správná odpověď je pouze „Divisible by 5“. Podle verze Javy, do které to dekompilujete, získáte buď funkci switch, nebo if else strom. V obou případech se hledá pouze první výskyt, ostatní nejsou brány v potaz.
public final void printPrimes(int num) { String var2; if (num % 5 == 0) { var2 = "Divisible by 5"; System.out.print(var2); } else if (num % 3 == 0) { var2 = "Divisible by 3"; System.out.print(var2); } else if (num % 2 == 0) { var2 = "Divisible by 2"; System.out.print(var2); } }
Streamy vs. Iterable
Od verze Javy 8 jsou programátoři zvyklí používat streamy na veškeré operace nad kolekcemi. V Kotlinu je to ještě jednodušší, protože ve standardní knihovně nalezneme všechny funkce, které poskytují streamy v Javě, přímo nad kolekcemi.
val values = listOf(1, 2, 3) values.filter { it > 1 }.map { it.toString() }.first()
Jednotlivé operace mají za výsledek novou kolekci. Každá další operace se tedy provádí vždy opět nad celou kolekcí. Pokud bychom se podívali, jak to vypadá v Javě, je to poněkud strašidelné.
List values = CollectionsKt.listOf(new Integer[]{1, 2, 3}); Iterable $this$map$iv = values; Collection destination$iv$iv = new ArrayList(); Iterator var7 = $this$map$iv.iterator(); Object item$iv$iv; int it; while(var7.hasNext()) { item$iv$iv = var7.next(); it = ((Number)item$iv$iv).intValue(); if (it > 1) { destination$iv$iv.add(item$iv$iv); } } $this$map$iv = (List)destination$iv$iv; destination$iv$iv = new ArrayList(CollectionsKt.collectionSizeOrDefault($this$map$iv, 10)); var7 = $this$map$iv.iterator(); while(var7.hasNext()) { item$iv$iv = var7.next(); it = ((Number)item$iv$iv).intValue(); String var12 = String.valueOf(it); destination$iv$iv.add(var12); } CollectionsKt.first((List)destination$iv$iv);
Tento přístup se nedoporučuje používat u kolekcí, které jsou objemné a provádí se nad nimi větší množství operací. V takovém případě se doporučuje používat sekvence. Sekvence jsou v Kotlinu ekvivalentem ke streamům v Javě, kdy se operace provádí optimálně vzhledem k ukončující podmínce.
Jediné, co je potřeba udělat navíc, je převést si seznam na sekvenci. Sekvence jsou označovány jako lazy a jednotlivé operace se dekorují další sekvencí, která obsahuje danou operaci. Výsledek se vypočítává až při určení ukončující operace.
val values = listOf(1, 2, 3) values.asSequence().filter { it > 1 }.map { it.toString() }.first()
List values = CollectionsKt.listOf(new Integer[]{1, 2, 3}); SequencesKt.first(SequencesKt.map(SequencesKt.filter(CollectionsKt.asSequence(values), (Function1)null.INSTANCE), (Function1)null.INSTANCE));
Budoucnost ve světě Javy
Kotlin si získal místo ve světě seriózních programovacích jazyků v roce 2017, kdy byl jmenován společností Google oficiálním jazykem pro vývoj aplikací pro platformu Android. V roce 2019 dokonce Kotlin nahradil Javu, jakožto preferovaný programovací jazyk pro platformu Android.
Já jsem se s Kotlinem poprvé setkal v roce 2019 na projektu v přední české bance a na stejném projektu působím doteď. Kotlin mě na první pohled uhranul svojí lehkostí a elegancí, kterou jsem do té doby ve světě Javy neznal. Kotlin nabízí nové možnosti, jak přemýšlet o problémech a jakým způsobem je řešit. Vývojář se mnohem častěji dostane do situace, kdy stejnou věc lze napsat více způsoby a záleží pak čistě na něm, zda si dokáže své řešení obhájit. Toto se dá samozřejmě chápat i negativně. Při nekoordinaci týmu vývojářů se lze snadno dostat do situace, ve které si každý člen dělá, co chce, a výsledkem je nečitelný balast. Každý tým by si měl stanovit vývojové guidelines, které bude dodržovat. V rámci nich má pak každý vývojář svobodu se realizovat dle své libosti.
S budoucností jazyka Kotlin to zatím vypadá slibně. Stále se vydávají nové verze, které opravují nalezené chyby, nebo se přidávají nové funkce. Oči vývojářů Kotlinu by se měly upínat k budoucí verzi Kotlinu 2.0, která představí Kotlin kompilátor K2. Ten zkrátí kompilaci kódu Kotlinu až na polovinu a umožní vývoj nových funkcionalit, které dosud nebyly se starým kompilátorem kompatibilní.
Pokud bychom se podívali na Google trends v porovnání obou jazyků ve světě za posledních 5 let, Kotlin si svojí pozici drží. Je to nicméně graf výskytů vyhledávání na Google, o skutečném počtu aktivních uživatelů to nemusí nic vypovídat.
Java se se svými verzemi snaží posouvat vpřed a s každou verzí přijít s něčím novým. V posledních verzích nám Java přinesla novinky, které vývojáři pracující v Kotlinu velmi dobře znají. Java od verze 17 obsahuje vylepšenou verzi funkce switch či sealed classes. Od verze 19 nabízí Java novinku virtuálních vláken, které konkurují coroutines z Kotlinu. Virtuální vlákna jsou nicméně stále v experimentální fázi a jejich použití ještě není ustálené napříč celou komunitou. Uvidíme, co v září přinese nová LTS verze Java 21.
Autor: Lukáš Rubeš