{"id":18624983,"url":"https://github.com/daverbk/kotlin","last_synced_at":"2025-11-03T19:30:34.729Z","repository":{"id":252702816,"uuid":"841180634","full_name":"daverbk/kotlin","owner":"daverbk","description":"Kotlin studies from scratch 😊","archived":false,"fork":false,"pushed_at":"2025-02-03T20:54:10.000Z","size":2557,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-03T21:34:24.415Z","etag":null,"topics":["kotlin","study"],"latest_commit_sha":null,"homepage":"https://kotlinlang.org/docs/kotlin-tour-hello-world.html","language":"Kotlin","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daverbk.png","metadata":{"files":{"readme":".github/README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"roadmap.pdf","authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-11T21:53:06.000Z","updated_at":"2025-02-03T20:54:13.000Z","dependencies_parsed_at":"2024-08-29T13:56:56.245Z","dependency_job_id":"78ec9fd2-254a-49cf-89b9-f04aab814ff9","html_url":"https://github.com/daverbk/kotlin","commit_stats":null,"previous_names":["daverbk/kotlin"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daverbk%2Fkotlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daverbk%2Fkotlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daverbk%2Fkotlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daverbk%2Fkotlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daverbk","download_url":"https://codeload.github.com/daverbk/kotlin/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239418579,"owners_count":19635208,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kotlin","study"],"created_at":"2024-11-07T04:32:18.976Z","updated_at":"2025-11-03T19:30:34.680Z","avatar_url":"https://github.com/daverbk.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [Kotlin Roadmap](../roadmap.pdf)\n\n\u003c!-- TOC --\u003e\n* [Kotlin Roadmap](#kotlin-roadmap)\n* [`class` / `object`](#class--object)\n  * [Modifiers](#modifiers)\n    * [`enum` class](#enum-class)\n    * [`data` class](#data-class)\n      * [`equals` and reference equality](#equals-and-reference-equality)\n    * [`sealed` class](#sealed-class)\n    * [Class delegation with `by`](#class-delegation-with-by)\n  * [Package structure](#package-structure)\n  * [Inheritance](#inheritance)\n  * [`object`](#object)\n    * [`companion object`](#companion-object)\n  * [Functions](#functions)\n    * [Constructors](#constructors)\n  * [Properties](#properties)\n    * [Lazy and late initialization](#lazy-and-late-initialization)\n* [Exceptions](#exceptions)\n* [Lambdas](#lambdas)\n  * [Extensions](#extensions)\n  * [Inline functions](#inline-functions)\n* [Nullability](#nullability)\n    * [Generics](#generics)\n* [Collections and Sequences](#collections-and-sequences)\n\u003c!-- TOC --\u003e\n\nKotlin is compiled to Java bytecode, which provides the backward compatability. When wishing to see Kotlin in real-life\nuse J2K converter can be used to convert part of source code into Kotlin. Another way is to start writing unit tests in\nKotlin.\n\nKotlin standard library is just Java standard library and a bunch of [extensions](#extensions) that provides very smooth\ninteroperability between Java code and Kotlin code.\n\nIn `IntelliJ` we can use the `Show Kotlin bytecode` + `Decompile` features to see the Java alternative for the Kotlin\ncode.\n\nReference on Kotlin conventions\n\n- [Kotlin for Java developers course part](https://www.coursera.org/learn/kotlin-for-java-developers/lecture/fZtQF/conventions)\n- [Kotlin coding conventions](https://kotlinlang.org/docs/coding-conventions.html)\n\n# `class` / `object`\n\n## Modifiers\n\nWe can declare constants with `const` modifier, and it's going to be substituted with the value on the JVM level. It\nworks only for primitive types.\n\n| modifier   | explanation                                                 |\n|------------|-------------------------------------------------------------|\n| `final`    | cannot be overridden (is sed by default)                    |\n| `open`     | can be overridden                                           |\n| `abstract` | must be overridden (can't have implementation)              |\n| `override` | overrides a member in a superclass or interface (mandatory) |\n\n| modifier    | class member                 | top-level declaration |\n|-------------|------------------------------|-----------------------|\n| `public`    | visible everywhere           | visible everywhere    |\n| `internal`  | visible in the module        | visible in the module |\n| `protected` | visible in subclasses (only) | –                     |\n| `private`   | visible in the class         | visible in the file   |\n\n| kotlin modifier | jvm level                     |\n|-----------------|-------------------------------|\n| `public`        | `public`                      |\n| `protected`     | `protected`                   |\n| `private`       | `private` / `package private` |\n| `internal`      | `public` \u0026 name ruining       |\n\n### `enum` class\n\nIn kotlin `enum` is a modifier for classes to create enumerations\n\n### `data` class\n\nGenerates `equals`, `hashCode`, `copy`, `toString`\n\n#### `equals` and reference equality\n\nIn kotlin `==` calls `equals`. There is also `===` operator which checks reference equality. Bare `class` `eqauls` uses\nreference equality check.\n\n```kotlin\nval set1 = setOf(1, 2, 3)\nval set2 = setOf(1, 2, 3)\n\nset1 == set2 // true\nset1 === set2 // false\n```\n\nWe can still exclude props from the basic methods in a `data class`by moving them outside the primary constructor.\n\n```kotlin\ndata class User(val email: String) {\n    val nickname: String? = null\n}\n```\n\n### `sealed` class\n\nRestricts class hierarchy, all subclasses must be located in the sames file.\n\n### Class delegation with `by`\n\nWe can delegate methods from one class another. We don't need to write boilerplate code for it.\n\n```kotlin\ninterface Printer {\n    fun printMessage(message: String)\n}\n\nclass ConsolePrinter : Printer {\n    override fun printMessage(message: String) {\n        pirntln(message)\n    }\n}\n\nclass PrinterManager(printer: Printer) : Printer by printer\n\nfun main() {\n    val consolePrinter = ConsolePrinter()\n    val manager = PrinterManager(consolePrinter)\n\n    manager.printMessage(\"Hi there!\") // \u003c-- we are calling a method, the code of which \n    // we did not write in PrinterManager explicitly\n}\n```\n\n## Package structure\n\nIn kotlin we can put multiple classes inside one file, this file can also contain top-level statements\n\n## Inheritance\n\n```kotlin\ninterface Base\nclass BaseImpl : Base\n```\n\n```kotlin\nopen class Parent\nclass Child : Parent() // \u003c-- () is the constructor call, so we can pass parameters there if any\n```\n\n## `object`\n\n`object` = singleton\n\n`java`\n\n```java\npublic class JSingleton {\n    public final static JSingleton INSTANCE = new JSingleton();\n\n    private JSignleton() {\n    }\n\n    private foo() {\n    }\n}\n```\n\n`kotlin`\n\n```kotlin\nobject KSingleton {\n    fun foo() {}\n}\n```\n\n### `companion object`\n\nIn kotlin there are no `static` methods and `companion object`s might be a replacement for that.\n\n```kotlin\nclass A {\n    companion object {\n        fun foo() = 1\n    }\n}\n\nfun main(args: Array\u003cString\u003e) {\n    A.foo()\n}\n```\n\nCompanion objects can implement interfaces and be receiver of extension function.\n\n```kotlin\ninterface Factory\u003cT\u003e {\n    fun create(): T\n}\n\nclass A {\n    private constructor()\n\n    companion object : Factory\u003cA\u003e {\n        override fun create(): A {\n            return A()\n        }\n    }\n}\n\nfun \u003cT\u003e createNewInstance(factory: Factory\u003cT\u003e) { /* some code */\n}\n\ncreateNewInstance(A)\nA.create()\n```\n\n```kotlin\nclass Person(val firstName: String, val lastName: String) {\n    companion object {}\n}\n\nfun Person.Companion.fromJson(json: String): Person {\n    // ... \n}\n\nval p = Person.fromJson(json)\n```\n\nNot all objects are singletons, object expressions are the java's anonymous class alternative. They are used for the\ncases when we have to override multiple methods, otherwise we could just use lambdas.\n\n```kotlin\nwidnow.addMouseListener() {\n    object : MouseAdapter() {\n        override fun mouseClicked(e: MouseEvent) {\n            // ..\n        }\n\n        override fun mouseEntered(e: MouseEvent) {\n            // ..\n        }\n    }\n}\n```\n\n## Functions\n\nThere are no `static` members in kotlin. The closest thing to that would be:\n\n- top-level statements\n- `object`s' members\n- `companion object`s' members\n\nCalling a top-level function from Java:\n\n```kotlin\npackage intro\n\nfun foo() = 0\n```\n\n```java\npackge other;\n\nimport intro.MyFileKt;\n\npublic class UsingFoo {\n    public static void main(String[] args) {\n        MyFileKt.foo();\n    }\n}\n```\n\nWe can use the `@JvmName` to change the name of the package to import.\n\n```kotlin\n@file:JvmName(\"Util\")\n\npackage intro\n\nfun foo() = 0\n```\n\n```java\npackge other;\n\nimport static intro.Util;\n\npublic class JavaUsage {\n    public static void main(String[] args) {\n        into i = Util.foo();\n    }\n}\n```\n\n### Constructors\n\n```kotlin\nclass A\n\nval a = A() // \u003c-- calling a default constructor \n```\n\nFull primary constructor syntax looks like this. `val` or `var` in the constructor would automatically create a\nproperty. Constructor's visibility can be changed.\n\n```kotlin\nclass Person(name: String) { // \u003c-- name is a constructor parameter\n    val name: String\n\n    init {\n        this.name = name\n    }\n}\n```\n\nWe can declare secondary constructors and must use the primary constructor.\n\n```kotlin\nclass Rectangle(val height: Int, val width: Int) {\n    constructor(side: Int) : this(side, side) { /* some logic */\n    }\n}\n```\n\n## Properties\n\n`Kotlin`\n\n```kotlin\ncontact.address\ncontact.address = \"...\"\n```\n\n`Java`\n\n```java\ncontact.getAddress();\ncontact.\n\nsetAdderss(\"...\");\n```\n\n`property` = `accessor(s)`\n\n`val` = `getter`\n\n`var` = `getter` + `setter`\n\nIf the `field` is not mentioned in custom accessor then no backing field is generated. All properties are `open`.\n\n### Lazy and late initialization\n\nLazy props' values is calculated on the first access.\n\n```kotlin\nval lazyValue: String by lazy {\n    println(\"completed!\")\n    \"Hello\"\n}\n```\n\n`lateinit` is useful when we want to initialize the values not in the constructor and not to use nullable accessors\neverywhere. If the property was not initialize a runtime `UninitializedPropertyAccessException` is thrown. `lateinit`\ncan't be `val`, can't be nullable or of a primitive type.\n\n```kotlin\nclass KotlinActivity : Activity() {\n    lateinit var myData: MyData\n\n    override fun onCreate(savedInstanceState: Budnle?) {\n        super.onCreate(savedInstanceState)\n\n        myData = intent.getParcelableExtra(\"MY_DATA\")\n    }\n}\n```\n\n```kotlin\nmyData.foo // we can call props of myData with no safe accessors\n```\n\n# Exceptions\n\nIn Kotlin, there is no difference between checked and unchecked exceptions. There are no checked exceptions in Kotlin so\nthere is no need to specify this function throws at this exception. Kotlin's library still has a `@Throws` annotation.\nWhen we throw a checked exception from Java point of view in Kotlin and want to later handle it in Java, we need to add\nthis annotation.\n\nJava code calling `foo()` won't compile.\n\n```kotlin\nfun foo() {\n    throw IOException()\n}\n```\n\nJava code calling `bar()` will compile.\n\n```kotlin\n@Throws(IOException::class)\nfun bar() {\n    throw IOException()\n}\n```\n\n# Lambdas\n\nIf lambda is the last argument in a function we can move it out of the presences\n\n```kotlin\nlist.any { i: Int -\u003e i \u003e 0 }\n```\n\n`it` or `this` can denote the argument if it's only one\n\n```kotlin\nlist.any { it \u003e 0 }\n```\n\nthe last expression is the result\n\n```kotlin\nlist.any {\n    println(\"processing $it\")\n    it \u003e 0 // is the same as return it \u003e 0\n}\n```\n\nwe can destruct arguments\n\n```kotlin\nmap.mapValues { (key, value) -\u003e \"$key -\u003e $value!\" }\n```\n\nexample of storing a lambda in a variable of type `(Int, Int) -\u003e Int`\n\n```kotlin\nval sum: (Int, Int) -\u003e Int = { x, y -\u003e x + y }\n```\n\nBound reference store the object on which the member can delay to called, while unbound can be called on any object of a\ngiven type\n\n`Bound`\n\n```kotlin\nclass Person(val name: String, val age: Int) {\n    fun isOlder(ageLimit: Int) = age \u003e ageLimit\n\n    fun getAgePredicate() = this::isOlder // \u003c- here is a bound reference\n}\n```\n\n`Unbound`\n\n```kotlin\nfun isEven(i: Int): Boolean = i % 2 == 0\n::isEven\n```\n\n`return` in lambdas\n\nA return inside a `fun` would return from the whole function\n\n```kotlin\nfun duplicateNonZero(list: List\u003cInt\u003e): List\u003cInt\u003e {\n    return list.flatMap {\n        if (it == 0) return listOf()\n        listOf(it, it)\n    }\n}\n\nprintln(duplicateNonZero(listOf(3, 0, 5))) // would return [] - an empty list \n```\n\nWe can specify what lambda to return from so that we do not return from the whole function (`@`)\n\n```kotlin\nfun duplicateNonZero(list: List\u003cInt\u003e): List\u003cInt\u003e {\n    return list.flatMap {\n        if (it == 0) return@flatMap listOf()\n        listOf(it, it)\n    }\n}\n```\n\nThe labeled return inside a `forEach` actually corresponds to java's `continue`\n\n```kotlin\nlist.forEach {\n    if (it == 0) return@forEach\n    println(it)\n}\n```\n\nis the same as\n\n```kotlin\nfor (element in list) {\n    if (element == 0) continue\n    print(element)\n}\n```\n\n## Extensions\n\nKotlin's extensions are basically static functions defined in a separate auxiliary class. We can't call private members\nfrom extensions. As extension functions are static under the hood they cannot be overridden. Properties can be extended.\n\n```kotlin\nfun String.lastChar() = this[this.length - 1]\n```\n\nReference of the [coding convention](https://kotlinlang.org/docs/coding-conventions.html#source-file-organization)\n\n... when defining extension functions for a class which are relevant for all clients of this class, put them in the same\nfile with the class itself. When defining extension functions that make sense only for a specific client, put them next\nto the code of that client. Avoid creating files just to hold all extensions of some class.\n\n## Inline functions\n\nInlining a function means that compiler will substitute a body of the function instead of calling it. No anonymous class\nwill be created for it.\n\n```kotlin\ninline fun \u003cR\u003e run(block: () -\u003e R): R = block()\n\nval name = \"Kotlin\"\nrun { println(\"Hi, $name!\") }\n```\n\nWill be compiled to the bytecode\n\n```kotlin\nval name = \"Kotlin\"\nprintln(\"Hi, $name!\") // inlined code of lambda body\n```\n\n### Resource management with `use`\n\n`java`\n\n```java\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.IOException;\n\nstatic String readFirstLineFormFile(String path) throws IOException {\n  try (BufferedReader br = new BufferedReader(new FileReader(path))) {\n    return br.readLine();\n  }\n}\n``` \n\n`kotlin`\n\n```kotlin\nimport java.io.BufferedReader\nimport java.io.FileReader\n\nfun readFirstLineFromFile(path: String): String {\n    BufferedReader(FileReader(path)).use { br -\u003e\n        return br.readLine()\n    }\n}\n```\n\n# Nullability\n\nKotlin took the approach of making NPE a compile-time exception. Each type is a child of the same nullable type. Under\nthe hood `fun foo(): String? = \"foo\"` is\n\n```java\n\n@Nullable\npublic static final String foo() {\n    return \"foo\";\n}\n```\n\n`fun bar(): String = \"bar\"` is\n\n```java\n\n@NotNull\npublic static final String foo() {\n    return \"foo\";\n}\n```\n\nOperators to work with nullability in Kotlin\n\n`!!`\n\n`s!!` - throws NPE if `s` is null\n\n`?.`\n\n```mermaid\nflowchart TD\n    expression[\"foo?.bar()\"] --\u003e|foo ! = null| value[\"foo.bar()\"]\n    expression --\u003e|foo = = null| null[null]\n```\n\n`?:`\n\n```mermaid\nflowchart TD\n    expression[\"foo ?: bar\"] --\u003e|foo ! = null| value[\"bar\"]\n    expression --\u003e|foo = = null| null[bar]\n```\n\n`as?`\n\n```mermaid\nflowchart TD\n    expression[\"foo as? Type\"] --\u003e|foo is Type| value[\"foo as Type\"]\n    expression --\u003e|foo !is Type| null[null]\n```\n\n### Generics\n\nA regular generic argument (`T` for example) can receive a nullable type. We can make it explicit.\n\n```kotlin\nfun \u003cT\u003e List\u003cT\u003e.firstOrNull(): T? {}\n```\n\nAt the same time we can set a non-nullable upper bound with `Any`.\n\n```kotlin\nfun \u003cT : Any\u003e foo(list: List\u003cT\u003e) {\n    for (element in list) {\n        \n    }\n}\n```\n\nIf we need to use multiple constraints for a type parameter we must use the `where`.\n\n```kotlin\nfun \u003cT\u003e ensureTrailingPeriod(seq: T) where T : CharSequence, T : Appendable {\n    if (!seq.endsWith('.')) {\n        seq.append('.')\n    }\n}\n```\n\nIn situations when generics result in the same JVM signature we must use `@JvmName` to resolve the conflict.\n\n```kotlin\nfun List\u003cInt\u003e.average(): Duble { }\n@JvmName(\"averageOfDouble\")\nfun List\u003cDouble\u003e.average(): Double { }\n```\n\n# Collections and Sequences\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaverbk%2Fkotlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaverbk%2Fkotlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaverbk%2Fkotlin/lists"}