elements_of_kotlin
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| elements_of_kotlin [2023/10/20 16:33] – [Getting Down in the Weeds] kalaschnikow | elements_of_kotlin [2023/10/24 16:36] (current) – [Abstract Classes and Interfaces] kalaschnikow | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Elements of Kotlin ====== | ||
| + | [[https:// | ||
| + | |||
| + | [[https:// | ||
| + | ===== Introducing Kotlin ===== | ||
| + | |||
| + | ==== Why? ==== | ||
| + | * 2017 - Kotlins popularity exploded as Google announced support for Kotlin for Android apps | ||
| + | * originally created as replacement for Java | ||
| + | * Kotlin is designed to be more concise as Java | ||
| + | * e.g. semicolon is optional in Kotlin | ||
| + | ==== ...And Why Not? ==== | ||
| + | * Kotlin is a complex language | ||
| + | * Kotlin lends itself to be terse | ||
| + | * " | ||
| + | * " | ||
| + | |||
| + | ==== What You Need to Know ==== | ||
| + | * class-based language | ||
| + | * like Java | ||
| + | * JavaScript previously was not, but now it is moved in this direction | ||
| + | * functions | ||
| + | * (" | ||
| + | * properties | ||
| + | * (" | ||
| + | * variables | ||
| + | * save working data inside functions | ||
| + | |||
| + | ==== Look At All the Kotlins! ==== | ||
| + | * Runtime environments to run compiled Kotlin code: | ||
| + | * Kotlin/ | ||
| + | * most used environment | ||
| + | * Kotlin/JS | ||
| + | * Kotlin " | ||
| + | * => simple JavaScript (but not really readable by humans :)) | ||
| + | * Kotlin/ | ||
| + | * mostly used in iOS environment | ||
| + | * Kotlin/ | ||
| + | * not really an environment | ||
| + | * it is a library that limits Kotlin code to guarantee that this code can be used all on other platforms (JVM, JS etc) | ||
| + | * Kotlin/ | ||
| + | * a way of setting up a project such that some core app logic is written in a Kotlin/ | ||
| + | * used for example to create one code base for Android and iOS apps | ||
| + | |||
| + | ==== Getting Kotlin, Normally ==== | ||
| + | |||
| + | * normally it will be done by IDE (for Android -> Android Studio) | ||
| + | * there are Gradle plugins for it etc | ||
| + | * it is also possible to download a standalone Kotlin compiler | ||
| + | |||
| + | ==== Introducing the Klassbook ==== | ||
| + | * An easy way to experiment with a programming language is to use a REPL. | ||
| + | * Read typed-in source code, | ||
| + | * Evaluate it, | ||
| + | * Print the results of that evaluation in the tool | ||
| + | * Loop back to process more input. | ||
| + | * [[https:// | ||
| + | ==== How This Book is Structured ==== | ||
| + | * This book has two objectives: | ||
| + | * Help you start writing basic Kotlin code | ||
| + | * Help you start reading advanced Kotlin code | ||
| + | * This book is divided into two major sets of chapters: | ||
| + | * core chapters | ||
| + | * basic Kotlin syntax | ||
| + | * mostly used Kotlin idioms | ||
| + | * “WTF?” chapters | ||
| + | * advanced Kotlin | ||
| + | |||
| + | |||
| + | ===== A Few “Hello, World!” Examples ===== | ||
| + | |||
| + | ... | ||
| + | |||
| + | ==== So, What Does This Do? ==== | ||
| + | |||
| + | ... | ||
| + | |||
| + | * '' | ||
| + | * In Kotlin: just use the class name like a function. So, '' | ||
| + | |||
| + | * Kotlin is a “strongly typed” language: everything in Kotlin is tied to some type. | ||
| + | |||
| + | ==== Using the Klassbook ==== | ||
| + | ... | ||
| + | |||
| + | ==== Running These Snippets in an IDE ==== | ||
| + | * Android Studio and IntelliJ IDEA each has a Kotlin REPL, available from the Tools > Kotlin > Kotlin REPL main menu option | ||
| + | * In Android Studio is also possible to use scratch files to run short examples | ||
| + | ===== Basic Types and Expressions ===== | ||
| + | |||
| + | Kotlin’s basic types are modeled somewhat after Java, as Kotlin’s original target environment was the JVM. | ||
| + | |||
| + | But there are also some differences. | ||
| + | |||
| + | ==== Basic Types and “Objectness” ==== | ||
| + | |||
| + | * In Kotlin everything is an object | ||
| + | * In Java: basic types are “primitives”, | ||
| + | * e.g. '' | ||
| + | |||
| + | ==== Numbers ==== | ||
| + | * There are four integral types: | ||
| + | * Byte (8-bit representation) | ||
| + | * Short (16 bits) | ||
| + | * Int (32 bits) | ||
| + | * Long (64 bits) | ||
| + | * Two floating-point types: | ||
| + | * Float (32 bits) | ||
| + | * Double (64 bits) | ||
| + | * Number Literals | ||
| + | * by default '' | ||
| + | * if you want a '' | ||
| + | * '' | ||
| + | * if you want a '' | ||
| + | * '' | ||
| + | * For longer numbers, if you like, you can use underscores for the “thousands separator”: | ||
| + | * '' | ||
| + | * Technically, | ||
| + | * For integral types, the default representation is decimal format. | ||
| + | * hexadecimal by using an '' | ||
| + | * '' | ||
| + | * binary literals by using an '' | ||
| + | * '' | ||
| + | * Mathematical Expressions | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * ''/'' | ||
| + | * '' | ||
| + | |||
| + | ==== Boolean ==== | ||
| + | * '' | ||
| + | * Boolean operators: | ||
| + | * ''&&'' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | ==== Strings ==== | ||
| + | |||
| + | * String Quoting Options | ||
| + | * two possible options: | ||
| + | * ''"'' | ||
| + | * like in Java | ||
| + | * cannot contain newlines | ||
| + | * special characters, such as newlines or tabs, need to be indicated via “escape sequences” | ||
| + | * '' | ||
| + | * ''"""'' | ||
| + | * does not support escape sequences but does support embedded newlines, tabs, and anything else | ||
| + | * this allows you to directly express strings that otherwise would be a mess of text and escape sequences, resulting in more readable code. | ||
| + | * but indents then become a problem | ||
| + | * use '' | ||
| + | * String Expressions | ||
| + | * Concatenation: | ||
| + | * Kotlin also supports " | ||
| + | * ''" | ||
| + | * ''" | ||
| + | |||
| + | ==== Characters ==== | ||
| + | |||
| + | * Use single quotes to declare a single character: | ||
| + | * '' | ||
| + | |||
| + | ==== A Quick Note About Equality ==== | ||
| + | |||
| + | * '' | ||
| + | * (like '' | ||
| + | * '' | ||
| + | * (like '' | ||
| + | |||
| + | * What you get as the result of an instance equality check ('' | ||
| + | |||
| + | <code kotlin> | ||
| + | val value = " | ||
| + | println(value.toUpperCase().toLowerCase() == value) | ||
| + | println(value.toUpperCase().toLowerCase() === value) | ||
| + | </ | ||
| + | ===== Variables… Whether They Vary or Not ===== | ||
| + | |||
| + | ==== Declaring Variables ==== | ||
| + | |||
| + | * Do you need a keyword, like var, or not? | ||
| + | * -> yes | ||
| + | * Do you need a data type, like int, or not? | ||
| + | * -> not always | ||
| + | * Do you need to provide an initializer to establish the variable’s value, or not? | ||
| + | * -> not always | ||
| + | |||
| + | * Typeless Declaration | ||
| + | * '' | ||
| + | * '' | ||
| + | * Typed Declaration | ||
| + | * '' | ||
| + | |||
| + | ==== Declaring Read-Only Variables ==== | ||
| + | |||
| + | * Declare " | ||
| + | * Reassigning value to a '' | ||
| + | * Prefer '' | ||
| + | * use '' | ||
| + | |||
| + | ==== String Interpolation ==== | ||
| + | |||
| + | * For a simple variable reference, you can skip the braces and just use $: | ||
| + | < | ||
| + | val count = 5 | ||
| + | println(" | ||
| + | </ | ||
| + | |||
| + | Arbitrary Kotlin expressions can be used with ${} syntax: | ||
| + | < | ||
| + | val count = 3 | ||
| + | println(" | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== More Operators ==== | ||
| + | |||
| + | * Mathematical expressions | ||
| + | * '' | ||
| + | * Increment and decrement | ||
| + | * postincrement++, | ||
| + | * postdecrement--, | ||
| + | * Augmented Assignments | ||
| + | * '' | ||
| + | * example: '' | ||
| + | * Unary Operators (inverting) | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | ==== No Automatic Number Conversions ==== | ||
| + | |||
| + | This will not work in Kotlin: | ||
| + | <code kotlin> | ||
| + | val thisIsInt = 5 | ||
| + | val thisIsLong : Long = thisIsInt | ||
| + | </ | ||
| + | (but it works in Java) | ||
| + | |||
| + | In Kotlin the code should be: | ||
| + | <code kotlin> | ||
| + | val thisIsInt = 5 | ||
| + | val thisIsLong : Long = thisIsInt.toLong() | ||
| + | </ | ||
| + | |||
| + | ==== Hey, What About ? ==== | ||
| + | * We can assign '' | ||
| + | <code kotlin> | ||
| + | var something : Boolean? = null | ||
| + | println(" | ||
| + | |||
| + | something = true | ||
| + | println(" | ||
| + | </ | ||
| + | |||
| + | |||
| + | ===== Functions ===== | ||
| + | |||
| + | ====Functions with Parameters==== | ||
| + | <code kotlin> | ||
| + | fun lessTrivial(left: | ||
| + | println(left + right) | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | At first the parameter name and then colon and the parameter type. | ||
| + | ====Functions with Return Types==== | ||
| + | |||
| + | <code kotlin> | ||
| + | fun simpleReturn(left: | ||
| + | return left + right | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | * Return type is at the end after the colon and before the curly brace ('' | ||
| + | * Functions without '' | ||
| + | ====Local Variables==== | ||
| + | |||
| + | <code kotlin> | ||
| + | fun actLocally(left: | ||
| + | val result = left + right | ||
| + | |||
| + | return result | ||
| + | } | ||
| + | </ | ||
| + | ====Fancier Functions==== | ||
| + | |||
| + | Expression bodies: | ||
| + | <code kotlin> | ||
| + | fun expressionBody(left: | ||
| + | </ | ||
| + | |||
| + | Expression Bodies and Types: | ||
| + | <code kotlin> | ||
| + | fun expressionBody(left: | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | |||
| + | Default parameter values: | ||
| + | <code kotlin> | ||
| + | fun main() { | ||
| + | println(increment(1)) | ||
| + | } | ||
| + | |||
| + | fun increment(base: | ||
| + | </ | ||
| + | |||
| + | Named parameters: | ||
| + | <code kotlin> | ||
| + | fun main() { | ||
| + | println(increment(base = 1)) | ||
| + | println(increment(amount = 10, base = 1)) | ||
| + | println(increment(1, | ||
| + | } | ||
| + | |||
| + | fun increment(base: | ||
| + | </ | ||
| + | |||
| + | It is a simple example and it does not make much sense. But sometimes it is really helpful. For example: | ||
| + | <code kotlin> | ||
| + | fun main() { | ||
| + | val cookieHeader = iCanHazCookie(name = " | ||
| + | |||
| + | // or even: | ||
| + | cookieHeader = iCanHazCookie(" | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | fun iCanHazCookie(name: | ||
| + | value: String, | ||
| + | maxAge: Long? = null, | ||
| + | expires: LocalDateTime? | ||
| + | domain: String? = null, | ||
| + | path: String? = null, | ||
| + | secure: Boolean = false, | ||
| + | httpOnly: Boolean = false) : String { | ||
| + | // code to generate an HTTP Set-cookie header goes here | ||
| + | // ... | ||
| + | } | ||
| + | </ | ||
| + | Traditionally, | ||
| + | ===== Collections and Lambdas ===== | ||
| + | Major collection types are like in the other popular modern languages: | ||
| + | * arrays or lists | ||
| + | * sets (collections of distinct unequal objects) | ||
| + | * maps (collections of key/value pairs) | ||
| + | |||
| + | ==== Major Collection Types and Creation Functions ==== | ||
| + | |||
| + | Kotlin has the aforementioned roster of collection types, and they form the most common collection types that you will use. | ||
| + | |||
| + | Kotlin/JVM also has access to other standard Java collection types, like LinkedHashMap, | ||
| + | |||
| + | * Arrays | ||
| + | * the simplest way to create an array: | ||
| + | * '' | ||
| + | * Typed arrays: | ||
| + | * '' | ||
| + | * They have corresponding utility functions to create instances, such as '' | ||
| + | * '' | ||
| + | * Lists | ||
| + | * can be created like Arrays: | ||
| + | * '' | ||
| + | * Sets | ||
| + | * is a one-dimensional collection in which only distinct objects will be included. | ||
| + | * For example, if you try adding the four numbers 1, 3, 3, 7 to a list, you would have four entries, but adding them to a set results in a three-element set holding 1, 3, 7. The duplicate 3 value is ignored. | ||
| + | * creation: | ||
| + | * '' | ||
| + | * (will contain only '' | ||
| + | * As with '' | ||
| + | * And, as with lists, '' | ||
| + | * Maps | ||
| + | * To create a hard-coded map — the way we have created hard-coded lists and sets — you can use the '' | ||
| + | * '' | ||
| + | * it is also possible to mix these constructs (e.g. use Lists as values for Maps) | ||
| + | * '' | ||
| + | |||
| + | ==== Basic Usage ==== | ||
| + | |||
| + | * [] Syntax | ||
| + | * To retrieve values from a collection (other than a Set), you can use []. For example: | ||
| + | * '' | ||
| + | * Typical Stuff | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * For lists and arrays, you have things like: | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * And so on | ||
| + | * Conversion Functions | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | |||
| + | |||
| + | ==== Immutability and Collections ==== | ||
| + | |||
| + | Array objects that we create with '' | ||
| + | |||
| + | <code kotlin> | ||
| + | val thingsArray = arrayOf(" | ||
| + | |||
| + | thingsArray[1] = " | ||
| + | </ | ||
| + | |||
| + | However, this fails if you try it with a List created using '' | ||
| + | <code kotlin> | ||
| + | val thingsList = listOf(" | ||
| + | |||
| + | thingsList[1] = " | ||
| + | </ | ||
| + | |||
| + | A List is immutable: you cannot replace its members with other objects. | ||
| + | |||
| + | If you need a list where you can replace its members, you can use '' | ||
| + | <code kotlin> | ||
| + | val thingsList = mutableListOf(" | ||
| + | |||
| + | thingsList[1] = " | ||
| + | </ | ||
| + | |||
| + | The same distinction holds true for '' | ||
| + | ==== Introducing Lambda Expressions ==== | ||
| + | * Lambda expressions are important to do the following: | ||
| + | * Looping over the elements | ||
| + | * Finding or filtering elements that match certain criteria | ||
| + | * Providing comparison logic for sorting elements | ||
| + | * ... | ||
| + | |||
| + | * What is a Lambda Expression? | ||
| + | * A simple way to start thinking about lambda expressions is to consider them just as a set of Kotlin statements wrapped in curly braces: | ||
| + | * '' | ||
| + | * A lambda expression itself is an object. | ||
| + | * You can hold onto them in variables, | ||
| + | * pass them as function parameters, | ||
| + | * and do everything else that you might do with other types of objects. | ||
| + | * If you receive a lambda expression, and you want to run it, call '' | ||
| + | <code kotlin> | ||
| + | val lambda = { println(" | ||
| + | |||
| + | lambda.invoke() | ||
| + | </ | ||
| + | * Where Do We Use Lambda Expressions? | ||
| + | * At minimum, lambda expressions replace a lot of the “listener” or “callback” patterns that you might have used in Java. | ||
| + | * Lambda Expressions, | ||
| + | * Like functions, lambda expressions can take parameters: | ||
| + | * <code kotlin> | ||
| + | val squarifier = { x: Int -> x * x } | ||
| + | |||
| + | println(squarifier.invoke(3)) | ||
| + | </ | ||
| + | * single-parameter lambdas are very common. For that, Kotlin offers a shorthand syntax: it. If the Kotlin compiler can determine the data type for the parameter, you can skip the parameter declaration and just refer to the parameter as it. | ||
| + | * A lambda expression will return whatever its last statement does. | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== Common Collection Operations ==== | ||
| + | |||
| + | * Iteration ('' | ||
| + | * '' | ||
| + | * <code kotlin> | ||
| + | val things = listOf(" | ||
| + | |||
| + | things.forEach { println(it) } | ||
| + | </ | ||
| + | * '' | ||
| + | * <code kotlin> | ||
| + | val things = listOf(" | ||
| + | |||
| + | things.forEach( { println(it) } ) | ||
| + | </ | ||
| + | * The lambda expression takes a single parameter. The type of the parameter is determined by the definition of '' | ||
| + | * '' | ||
| + | * <code kotlin> | ||
| + | val things = listOf(" | ||
| + | |||
| + | for (thing in things) { | ||
| + | println(thing) | ||
| + | } | ||
| + | </ | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * <code kotlin> | ||
| + | val things = listOf(" | ||
| + | |||
| + | things.filter { it[1]==' | ||
| + | </ | ||
| + | * '' | ||
| + | * '' | ||
| + | * <code kotlin> | ||
| + | val things = listOf(" | ||
| + | |||
| + | things | ||
| + | .map { it.toUpperCase() } | ||
| + | .forEach { println(it) } | ||
| + | </ | ||
| + | * whereas '' | ||
| + | |||
| + | ==== Varargs ==== | ||
| + | <code kotlin> | ||
| + | fun main() { | ||
| + | reciprocate(1, | ||
| + | } | ||
| + | |||
| + | fun reciprocate(vararg values: Int) { | ||
| + | values | ||
| + | .map { 1.0 / it } | ||
| + | .forEach { println(it) } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | In addition, Kotlin offers special support for an existing Array. If you already have an Array with the values that you want to supply, but the function that you are calling uses vararg (instead of an Array parameter), you can use the “spread operator” | ||
| + | <code kotlin> | ||
| + | fun main() { | ||
| + | val things = arrayOf(" | ||
| + | |||
| + | capped(*things).forEach { println(it) } | ||
| + | } | ||
| + | |||
| + | fun capped(vararg strings: String) = strings.map { it.toUpperCase() } | ||
| + | </ | ||
| + | |||
| + | Things get a bit strange with types that map to primitives, though. '' | ||
| + | <code kotlin> | ||
| + | fun main() { | ||
| + | val primes = intArrayOf(1, | ||
| + | |||
| + | reciprocate(*primes) | ||
| + | } | ||
| + | |||
| + | fun reciprocate(vararg values: Int) { | ||
| + | values | ||
| + | .map { 1.0 / it } | ||
| + | .forEach { println(it) } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Other JVM Collections ==== | ||
| + | If you are using Kotlin/JVM — for example, if you are using Kotlin for ordinary Android app development — you are welcome to use other JVM collection types, such as '' | ||
| + | ==== get() and [] Syntax ==== | ||
| + | In reality, '' | ||
| + | |||
| + | |||
| + | ===== If, When, and While ===== | ||
| + | |||
| + | ==== If ==== | ||
| + | |||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | if (i > 10) { | ||
| + | println(" | ||
| + | } | ||
| + | else { | ||
| + | println(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | if (i > 10) { | ||
| + | println(" | ||
| + | } | ||
| + | |||
| + | println(" | ||
| + | </ | ||
| + | |||
| + | For single-line conditional work, you can skip the braces: | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | if (i>10) println(" | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | if (i > 10) { | ||
| + | println(" | ||
| + | } | ||
| + | else if (i > 2) { | ||
| + | println(" | ||
| + | } | ||
| + | else { | ||
| + | println(" | ||
| + | } | ||
| + | </ | ||
| + | However, as you will see in the next section, the convention in Kotlin development is to use '' | ||
| + | ==== When ==== | ||
| + | |||
| + | Basic syntax: | ||
| + | |||
| + | <code kotlin> | ||
| + | val thingy = " | ||
| + | |||
| + | when (thingy) { | ||
| + | " | ||
| + | " | ||
| + | else -> println(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | However, you cannot mix types, unless == happens to work to compare them. | ||
| + | |||
| + | It is possible to skip the parameter to the '' | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | when { | ||
| + | i > 10 -> println(" | ||
| + | i > 2 -> println(" | ||
| + | else -> println(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Also we can consolidate multiple branches: | ||
| + | <code kotlin> | ||
| + | val thingy = " | ||
| + | |||
| + | when (thingy) { | ||
| + | " | ||
| + | " | ||
| + | else -> println(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | For numbers, you can use '' | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | when (i) { | ||
| + | in 3..10 -> println(" | ||
| + | in 1..2 -> println(" | ||
| + | else -> println(" | ||
| + | } | ||
| + | </ | ||
| + | However, these simplifications only work when you supply a value to '' | ||
| + | |||
| + | The value for comparison does not need to be a constant — any expression will also work: | ||
| + | <code kotlin> | ||
| + | val thingy = " | ||
| + | val otherThingy = " | ||
| + | |||
| + | when (thingy) { | ||
| + | " | ||
| + | otherThingy.toLowerCase() -> println(" | ||
| + | else -> println(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== While ==== | ||
| + | |||
| + | <code kotlin> | ||
| + | var i = 0 | ||
| + | |||
| + | while (i < 10) { | ||
| + | i++ | ||
| + | println(i) | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | However, '' | ||
| + | ==== If/When As Expressions ==== | ||
| + | Kotlin lacks ternary support, but more than makes up for it by allowing if to serve in the same role: | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | val j = if(i < 2) 2 else i | ||
| + | </ | ||
| + | |||
| + | Also possible with braces: | ||
| + | <code kotlin> | ||
| + | val bar = 5 | ||
| + | val foo = if (bar > 10) { | ||
| + | 10 | ||
| + | } | ||
| + | else { | ||
| + | bar | ||
| + | } | ||
| + | |||
| + | println(foo) | ||
| + | </ | ||
| + | The value of the last statement of the block is what that block evaluates to. In this case, each of those blocks is a single statement, but if we had several statements in a block, while they are all executed, the value from the last statement is used for the result (assuming that block is used, based on the conditional expression). | ||
| + | |||
| + | '' | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | val message = when (i) { | ||
| + | in 3..10 -> " | ||
| + | in 1..2 -> " | ||
| + | else -> "and now for something completely different" | ||
| + | } | ||
| + | |||
| + | println(message) | ||
| + | </ | ||
| + | |||
| + | In the situations, when '' | ||
| + | <code kotlin> | ||
| + | val i = 3 | ||
| + | |||
| + | val message = when (i) { | ||
| + | in 3..10 -> " | ||
| + | in 1..2 -> 5 | ||
| + | } | ||
| + | |||
| + | println(message) | ||
| + | </ | ||
| + | …you will get a compiler error. Because it is not clear what should be done in '' | ||
| + | |||
| + | |||
| + | ==== Bustin’ Out ==== | ||
| + | |||
| + | You can always use return to exit the entire function that you are in. Beyond that, though, there are two loop control statements that you can use: '' | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | ===== Basic Classes ===== | ||
| + | |||
| + | ====Basic Classes==== | ||
| + | A class does not have to contain any of that — this is a valid Kotlin class definition: | ||
| + | <code kotlin> | ||
| + | class Foo { | ||
| + | | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | This is also valid: | ||
| + | <code kotlin> | ||
| + | class Foo | ||
| + | </ | ||
| + | |||
| + | Having a class with no body seems odd. However, in Kotlin, you will occasionally see that sort of thing, particularly with data classes and sealed classes. However, most ordinary classes will have properties and functions. | ||
| + | |||
| + | ====Creating Instances of Classes==== | ||
| + | |||
| + | To create an instance of a class it is not necessary to use '' | ||
| + | |||
| + | <code kotlin> | ||
| + | class Foo | ||
| + | |||
| + | fun main() { | ||
| + | val foo = Foo() | ||
| + | |||
| + | println(foo) | ||
| + | } | ||
| + | </ | ||
| + | ====Packages==== | ||
| + | The syntax to declare package is Java-like: | ||
| + | |||
| + | <code kotlin> | ||
| + | package bar.goo | ||
| + | |||
| + | class Foo | ||
| + | |||
| + | val foo = Foo() | ||
| + | |||
| + | </ | ||
| + | ====Common Contents==== | ||
| + | |||
| + | === Functions === | ||
| + | <code kotlin> | ||
| + | class Foo { | ||
| + | fun something() { | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fun main() { | ||
| + | val foo = Foo() | ||
| + | |||
| + | foo.something() | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Properties === | ||
| + | Classes can also have properties: | ||
| + | <code kotlin> | ||
| + | class Foo { | ||
| + | var count = 0 | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fun main() { | ||
| + | val foo = Foo() | ||
| + | |||
| + | foo.something() | ||
| + | foo.something() | ||
| + | foo.something() | ||
| + | |||
| + | println(" | ||
| + | } | ||
| + | </ | ||
| + | ====this==== | ||
| + | |||
| + | As with Java, Kotlin uses this as a pseudo-property to refer to the instance of the object in whose function you happen to be running. | ||
| + | |||
| + | <code kotlin> | ||
| + | class Foo { | ||
| + | var count = 0 | ||
| + | |||
| + | fun something() { | ||
| + | this.count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | ====Constructors==== | ||
| + | |||
| + | The way you will normally see Kotlin classes have a constructor is by making the actual class name itself take the constructor parameters: | ||
| + | <code kotlin> | ||
| + | class Foo(var count: Int) { | ||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | fun main() { | ||
| + | val foo = Foo(0) | ||
| + | |||
| + | foo.something() | ||
| + | foo.something() | ||
| + | foo.something() | ||
| + | |||
| + | println(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | The constructor syntax shown above is really a shorthand for using the constructor keyword: | ||
| + | <code kotlin> | ||
| + | class Foo constructor(var count: Int) { | ||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | // ... | ||
| + | </ | ||
| + | |||
| + | === Init Blocks === | ||
| + | |||
| + | Syntax-wise, | ||
| + | <code kotlin> | ||
| + | class Foo(val sillyCount: String) { | ||
| + | var count = 0 | ||
| + | |||
| + | init { | ||
| + | count = sillyCount.toInt() | ||
| + | } | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | |||
| + | fun main() { | ||
| + | val foo = Foo(" | ||
| + | |||
| + | foo.something() | ||
| + | foo.something() | ||
| + | foo.something() | ||
| + | |||
| + | println(" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | |||
| + | * You can have more than one '' | ||
| + | * An '' | ||
| + | * Sometimes, you will see constructor parameters that do not have the '' | ||
| + | |||
| + | === Having Multiple Constructors === | ||
| + | The primary constructor appears in the class declaration itself, as we have seen. Other constructors, | ||
| + | <code kotlin> | ||
| + | class Foo(var count: Int) { | ||
| + | |||
| + | constructor(sillyCount: | ||
| + | // could have code here if needed | ||
| + | } | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | |||
| + | |||
| + | fun main() { | ||
| + | val foo = Foo(" | ||
| + | |||
| + | foo.something() | ||
| + | foo.something() | ||
| + | foo.something() | ||
| + | |||
| + | println(" | ||
| + | } | ||
| + | </ | ||
| + | A primary constructor has no function body — any such code goes into an '' | ||
| + | |||
| + | Secondary constructors //must// arrange to //call the primary constructor// | ||
| + | |||
| + | === Default Parameter Values === | ||
| + | Kotlin supports default parameter values in constructors: | ||
| + | <code kotlin> | ||
| + | |||
| + | |||
| + | class View( | ||
| + | context: Context, | ||
| + | attrs: AttributeSet? | ||
| + | defStyleAttr: | ||
| + | defStyleRes: | ||
| + | ) { | ||
| + | // two tons of code | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Here, the latter three parameters all have default values defined, giving us the ability to call the constructor with one parameter, all four parameters, or combinations in between. | ||
| + | ====Inheritance==== | ||
| + | Kotlin uses colons to indicate inheritance: | ||
| + | <code kotlin> | ||
| + | class Foo(var count: Int) : Any() { | ||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | (the Java counterpart is the keyword '' | ||
| + | |||
| + | Chaining the super class contructor: | ||
| + | <code kotlin> | ||
| + | open class Base(val tag: String) | ||
| + | |||
| + | class Foo(var count: Int) : Base(" | ||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | In Java, by default, any class can be extended by a subclass. To prevent a class from being extended, you have to mark it as '' | ||
| + | |||
| + | Kotlin goes the opposite route. Kotlin classes //cannot be extended by default//. You have to mark classes that can be extended using '' | ||
| + | |||
| + | === Overriding Functions === | ||
| + | * A subclass can call functions that it inherits from its superclass. | ||
| + | * A subclass can override functions of its superclasses… at least, if those too are marked as '' | ||
| + | |||
| + | <code kotlin> | ||
| + | open class Base(val tag: String) { | ||
| + | open fun gimmeTheTag() = tag | ||
| + | } | ||
| + | |||
| + | class Foo(var count: Int) : Base(" | ||
| + | override fun gimmeTheTag() = "Not the Original Tag" | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | * By default, '' | ||
| + | * unless the class which overrides the functions marks its version of that function as '' | ||
| + | |||
| + | === Overriding Properties === | ||
| + | It is also possible for a class to declare a property as '' | ||
| + | <code kotlin> | ||
| + | open class Base(open val tag: String) { | ||
| + | open fun gimmeTheTag() = tag | ||
| + | } | ||
| + | |||
| + | open class Intermezzo(override val tag: String) : Base(tag) | ||
| + | |||
| + | class Foo(var count: Int) : Intermezzo(" | ||
| + | override fun gimmeTheTag() = "Not the Original Tag" | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Chaining to Superclass Functions === | ||
| + | |||
| + | <code kotlin> | ||
| + | open class Base(val tag: String) { | ||
| + | open fun gimmeTheTag() = tag | ||
| + | } | ||
| + | |||
| + | class Foo(var count: Int) : Base(" | ||
| + | override fun gimmeTheTag() = super.gimmeTheTag() + " | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Inheritance Tests === | ||
| + | Kotlin has syntax similar to Java's '' | ||
| + | <code kotlin> | ||
| + | open class Animal | ||
| + | |||
| + | class Frog : Animal() | ||
| + | |||
| + | class Axolotl : Animal() | ||
| + | |||
| + | fun main() { | ||
| + | val critter: Animal = Frog() | ||
| + | |||
| + | if (critter is Frog) println(" | ||
| + | } | ||
| + | </ | ||
| + | In Kotlin, we can use is not only as part of an expression, but we can use it as a test for a when clause. We can rewrite the previous example using a when: | ||
| + | <code kotlin> | ||
| + | open class Animal | ||
| + | |||
| + | class Frog : Animal() | ||
| + | |||
| + | class Axolotl : Animal() | ||
| + | |||
| + | fun main() { | ||
| + | val critter: Animal = Frog() | ||
| + | |||
| + | when (critter) { | ||
| + | is Frog -> println(" | ||
| + | else -> println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Casting === | ||
| + | In Kotlin, casting is performed by using the '' | ||
| + | <code kotlin> | ||
| + | val critter: Animal = Frog() | ||
| + | val kermit = critter as Frog | ||
| + | </ | ||
| + | |||
| + | Inside of '' | ||
| + | <code kotlin> | ||
| + | open class Animal | ||
| + | |||
| + | class Frog : Animal() { | ||
| + | fun hop() = println(" | ||
| + | } | ||
| + | |||
| + | class Axolotl : Animal() { | ||
| + | fun swim() = println(" | ||
| + | } | ||
| + | |||
| + | fun main() { | ||
| + | val critter: Animal = Frog() | ||
| + | |||
| + | when (critter) { | ||
| + | is Frog -> critter.hop() | ||
| + | is Axolotl -> critter.swim() | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | In a Java-style world, this would not compile. critter is an Animal, and Animal has neither hop() nor swim(). However, Kotlin realizes that the is Frog code will only be executed if critter is a Frog, so it allows us to call hop() on critter, as if critter were declared as a Frog instead of as an Animal. Similarly, we can call swim() on critter if it is Axolotl. | ||
| + | |||
| + | But this works only if compiler is sure. This code will not compile, because it is unclear in '' | ||
| + | <code kotlin> | ||
| + | //... | ||
| + | when (critter) { | ||
| + | is Frog -> critter.hop() | ||
| + | else -> critter.swim() | ||
| + | } | ||
| + | //... | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== Comments and Documentation ===== | ||
| + | ==== Basic Comment Syntax ==== | ||
| + | All is like in Java. With one exception: | ||
| + | |||
| + | The biggest — and perhaps only — difference between Kotlin comments and what you might do in Java is that multi-line comments can be nested in Kotlin. | ||
| + | |||
| + | ==== Introducing KDoc ==== | ||
| + | |||
| + | Kotlin’s equivalent to JavaDoc is KDoc. | ||
| + | |||
| + | Where KDoc breaks from JavaDoc is in terms of text formatting. KDoc uses [[https:// | ||
| + | |||
| + | What Markdown lacks is a way to link to things inside the same document. KDoc extends Markdown linking syntax, allowing you to reference properties, functions, and similar named things by using simple bracket syntax: | ||
| + | <code kotlin> | ||
| + | /** | ||
| + | * This is the summary of your Kotlin class. It should explain, in a single | ||
| + | * paragraph, the role of this class in your project. | ||
| + | * | ||
| + | * This class has a single function: [something]. | ||
| + | * | ||
| + | * You can also link to other classes, such as [kotlin.String], | ||
| + | * fully-qualified class name. | ||
| + | * | ||
| + | * And, of course, you can [link to external content](https:// | ||
| + | */ | ||
| + | </ | ||
| + | |||
| + | As with JavaDoc, KDoc supports “block tags” for documenting sub-elements of class, function, etc. For example, you can use @param to document a function parameter, @return to document a function return value, and so forth. | ||
| + | |||
| + | Just as Java has a javadoc program to generate JavaDocs, Kotlin has a similar tool: [[https:// | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== Properties ===== | ||
| + | ==== Initialization ==== | ||
| + | |||
| + | Properties need to be initialized at some point. | ||
| + | |||
| + | Initialization when declared ('' | ||
| + | <code kotlin> | ||
| + | class Foo(sillyCount: | ||
| + | var count = sillyCount.toInt() | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | In an '' | ||
| + | <code kotlin> | ||
| + | class Foo(sillyCount: | ||
| + | var count: Int | ||
| + | |||
| + | init { | ||
| + | count = sillyCount.toInt() | ||
| + | } | ||
| + | // ... | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Initialization " | ||
| + | <code kotlin> | ||
| + | class Foo { | ||
| + | var count = 0 | ||
| + | lateinit var label: String | ||
| + | |||
| + | fun defineTag(tag: | ||
| + | label = tag | ||
| + | } | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | But in this case the function '' | ||
| + | |||
| + | Also note that '' | ||
| + | |||
| + | Yet another possibility is to use '' | ||
| + | <code kotlin> | ||
| + | class Foo(val rawLabel: String) { | ||
| + | var count = 0 | ||
| + | val label: String by lazy { println(" | ||
| + | |||
| + | fun something() { | ||
| + | count += 1 | ||
| + | println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Here, '' | ||
| + | |||
| + | One more way to initialize property is to use a function like property. In Kotlin it is possible to call function without parethesis (e.g. '' | ||
| + | ==== Constants ==== | ||
| + | |||
| + | Kotlin has a '' | ||
| + | ==== Getting Down in the Weeds ==== | ||
| + | |||
| + | A Kotlin property really represents the combination of these three elements: | ||
| + | * a field | ||
| + | * a getter function | ||
| + | * a setter function | ||
| + | |||
| + | It is something like JavaBeans, but without the need to implement standard getter and setter. | ||
| + | |||
| + | Some advanced Kotlin syntax — such as the “fake properties” alluded to earlier — take advantage of this, overriding the default getter and/or setter to do something else. But in the most cases the standard is enough. | ||
| + | |||
| + | |||
| + | |||
| + | ===== Visibility and Scope ===== | ||
| + | |||
| + | * Visibility: What is allowed to see these classes, functions, and properties? | ||
| + | * Scope: Where do these classes, functions, and properties actually exist? | ||
| + | |||
| + | |||
| + | ==== Visibility ==== | ||
| + | |||
| + | * '' | ||
| + | * Kotlin takes the public-by-default route. Everything that is defined by default is visible to anything else. | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | * '' | ||
| + | * The '' | ||
| + | * '' | ||
| + | |||
| + | * '' | ||
| + | * Kotlin **does not offer package-private visibility**. | ||
| + | |||
| + | * '' | ||
| + | * anything marked as '' | ||
| + | * strange -> the meaning of the " | ||
| + | * So, if you plan on publishing some form of Kotlin library, '' | ||
| + | * On a large project that you have divided into modules, '' | ||
| + | * For small single-module projects, '' | ||
| + | ==== Scope ==== | ||
| + | |||
| + | * Global | ||
| + | * Top-level definitions in a Kotlin source file are global in scope. | ||
| + | * Immutable globals — classes, '' | ||
| + | * Mutable globals — such as '' | ||
| + | |||
| + | * Instance | ||
| + | * Properties defined inside of a class have “instance” scope. Each instance of the enclosing class will have its own set of instance properties, independent of any other instance of that same class. | ||
| + | |||
| + | * Local | ||
| + | * Local to Functions | ||
| + | * Local to Blocks/ | ||
| + | ===== Abstract Classes and Interfaces ===== | ||
| + | |||
| + | * -> https:// | ||
| + | |||
| + | |||
| + | ==== The Objective: Contracts ==== | ||
| + | |||
| + | ==== Abstract Classes ==== | ||
| + | |||
| + | ==== Interfaces ==== | ||
| + | |||
| + | ==== Which Do You Use? ==== | ||
| + | |||
| + | |||
| + | ===== Data Class ===== | ||
| + | ===== The object Keyword ===== | ||
| + | ===== Nested Objects and Classes ===== | ||
| + | ===== Enums and Sealed Classes ===== | ||
| + | ===== Generics ===== | ||
| + | ===== Exceptions ===== | ||
| + | ===== Annotations ===== | ||
| + | ===== Nullability ===== | ||
| + | ===== Scope Functions ===== | ||
| + | ===== Functional Programming ===== | ||
| + | ===== Extension Functions ===== | ||
| + | ===== Java Interoperability ===== | ||
| + | ===== Changes in Newer Kotlin Versions ===== | ||
| + | ===== Custom Accessors ===== | ||
| + | ===== Extension Properties ===== | ||
| + | ===== Escaping Keywords ===== | ||
| + | ===== Escaped Method Names ===== | ||
| + | ===== Property Delegates ===== | ||
| + | ===== Class Delegation ===== | ||
| + | ===== Constants ===== | ||
| + | ===== Abstract Properties ===== | ||
| + | ===== Covariance in Generics ===== | ||
| + | ===== Contravariance in Generics ===== | ||
| + | ===== Anonymous Functions ===== | ||
| + | ===== Local Functions ===== | ||
| + | ===== Local Types ===== | ||
| + | ===== Inline Functions ===== | ||
| + | ===== Inline Classes ===== | ||
| + | ===== Reified Type Parameters ===== | ||
| + | ===== noinline and crossinline ===== | ||
| + | ===== Receivers in Function Types ===== | ||
| + | ===== Renamed Imports ===== | ||
| + | ===== Operator Overloading ===== | ||
| + | ===== Infix Functions ===== | ||
| + | ===== Destructuring Declarations ===== | ||
| + | ===== Labeled Returns ===== | ||
| + | ===== Nothing ===== | ||
| + | ===== Types of Keywords ===== | ||
