20 posts
Learn Kotlin by Example
[Learn Kotlin by Example](https://play.kotlinlang.org/byExample/overview?_gl=1*9t8fde*_gcl_au*MTMyMjIyOTg2NC4xNzI5Nz Q0OTky*_ga*MjIxOTA3MTMxLjE3Mjk3NDQ5ODg.*_ga_9J976DJZ68*MTcyOTc0NDk4OC4xLjEuMTcyOTc0NjM2OS41OC4wLjA.) All examples in this article are taken from the Kotlin doc. I did not organize all the contents, but added important contents excluding the basic contents such as Starting Kotlin below.
Kotlin types
Kotlin does not distinguish between primitive types and wrapper types. Basically, it is automatically converted to Java's primitive type and wrapper type at compile time without using the primitive type, that is, it is converted to the primitive type at compile time, and the converted bytecode is executed at runtime. The top type includes Any type and is used like Java's Object type. It is also a parent object of other Int and Boolean primitive types. The Unit type is marked as having no return, like void in Java, and there is no need to use an explicit return. You can see that there are no methods actually written and that they are created as singletons. You can see that the Nothing type is a function that does not terminate normally. Used as a type for functions that contain infinite loops or always throw exceptions. 🍎
infix function 🍎
It is a function that goes in between two objects and can be applied to the function using dispatcher, the object before the function, and receiver, the object after the function. Inside a class, dispatcher can be implemented by the class itself without having to define it separately.
infix fun Int.shl(x: Int): Int { ... }
1 shl 2
1.shl(2)
vararg parameters 🍎
Allows you to divide the given value based on a comma (,) and use it like an array.
fun printAll(vararg messages: String) {
for (m in messages) println(m)
}
printAll("Hello", "Hallo", "Salut", "Hola", "你好")
Null safety
If you want to use null, when declaring a variable, you must use ? in the type to indicate that null can be entered as an argument. ? is a nullable type, and if you try to use null where it is not allowed, a compilation error will occur.
var nullable: String? = "You can keep a null here"
class
The default constructor is automatically generated in Kotlin. Unlike java, you do not need to indicate new when creating a default constructor.
Data class
Methods such as toString, copy, and componentN are automatically created, and to find an exact matching element, you can check whether hashCode matches.
println(user.hashCode())
Enum class
Enum can add the value of each property, and you can add a method to check whether there is a match using that property. 🍎
fun containsRed() = (this.rgb and 0xFF0000 != 0)
// 이런 방식으로 빨간색의 포함여부를 확인할 수 있다.
Sealed classes
This is a class used to limit inheritance.
sealed class Mammal(val name: String) // 1
class Cat(val catName: String) : Mammal(catName) // 2
class Human(val humanName: String, val job: String) : Mammal(humanName)
fun greetMammal(mammal: Mammal): String {
when (mammal) { // 3
is Human -> return "Hello ${mammal.name}; You're working as a ${mammal.job}" // 4
is Cat -> return "Hello ${mammal.name}" // 5
} // 6
}
- Cast mammal to Human or Cat in when
- Need to handle non-sealed classes
#####object 🍎 A lazy instance is an object that is used once, like a singleton in Java. The moment you call a function, an object object is created inside the function.
fun rentPrice(standardDays: Int, festivityDays: Int, specialDays: Int): Unit {
val dayRates = object {
var standard: Int = 30 * standardDays
var festivity: Int = 50 * festivityDays
var special: Int = 100 * specialDays
}
}
When declaring an object, unlike the expression above, there is a difference in that it cannot be used in the form of variable assignment and must be accessed immediately.
object DoAuth {
fun takeParams(username: String, password: String) {
println("input Auth parameters = $username:$password")
}
}
A companion object is used like static in Java, allowing it to be used globally. When used, it can be used as a package level function.
class BigBen {
companion object Bonger {
fun getBongs(nTimes: Int) {
for (i in 1 .. nTimes) {
print("BONG ")
}
}
}
}
Generics 🍎
E is an Element parameter that represents the generic type. E or any type can be used in this place. And the return refrain can also be done with E.
Generic functions place <E> in front of the function name to make it clear what type is specified when calling the function.
fun <E> mutableStackOf(vararg elements: E) = MutableStack(*elements)
Inheritance
Use open to make a class inheritable.
Control Flow
when
In Kotlin, you can easily perform value-dependent processing within parentheses by using when instead of switch.
fun whenAssign(obj: Any): Any {
val result = when (obj) {
1 -> "one"
"Hello" -> 1
is Long -> false
else -> 42
}
return result
}
iterators 🍎
Provides functions such as next() and hasNext() as a way to consistently retrieve the values of collections (Set, List, Map).
class Zoo(val animals: List<Animal>) {
operator fun iterator(): Iterator<Animal> { // 1
return animals.iterator() // 2
}
}
ranges
In loop statements such as for loops, you can use various expressions to determine the scope of repetition, as follows:
- for(i in 0...3)
- for(i in 0 until 3)
- for(i in 2...8 step 2)
- for(i in 3 downTo 0)
Equality Checks
In Kotlin, == returns true if the structural match is the same, and === returns true only if the element matches are identical. 🍎
val authors = setOf("Shakespeare", "Hemingway", "Twain")
val writers = setOf("Twain", "Shakespeare", "Hemingway")
println(authors == writers) // 1
println(authors === writers) // 2
Functional
A function can be used as a parameter or as a return function.
In the code below, if you receive and use a function as ::sum in a function called calculate or calculate multiplication, you can perform the operation as specified in calculate.
val sumResult = calculate(4, 5, ::sum)
val mulResult = calculate(4, 5) { a, b -> a * b }
Since the operation returns a ::square function, 2*2 is performed.
fun operation(): (Int) -> Int {
return ::square
}
fun square(x: Int) = x * x
fun main() {
val func = operation()
println(func(2))
}
You can simply display a function using lambda as follows.
val upperCase6: (String) -> String = String::uppercase
Extension function
You can create extensible functions without inheritance or other design patterns. Extension properties are also supported. Even if you did not create a function in the class itself, you can define an extension function using . in the class without a new member.
fun Order.maxPricedItemValue(): Float = this.items.maxByOrNull { it.price }?.price ?: 0F
Collections
Listis a collection that can only be read, andMutableListis a mutable collection.Setis unordered and does not allow duplicates.MutableSet, likeMutableList, is a mutable collection.MutableMapis a mutable collection.
val EZPassAccounts: MutableMap<Int, Int> = mutableMapOf(1 to 100, 2 to 100, 3 to 100)
- You can use
filterto extract only those elements that meet a condition among the given object elements. mapallows you to operate on all elements of a given object.any,all, andnoneall check whether all or none of the elements matching the condition exist in the given object and return a boolean value.associateByandgroupBycreate a map using collection elements with a specified key. 🍎- You can see in the results below that the output value is different depending on how the function is used. You can make only specific elements appear from an object, such as
Person::phone, or you can make all elements centered around the valuephone, like{ it.phone }.
data class Person(val name: String, val city: String, val phone: String)
val people = listOf(
Person("John", "Boston", "+1-888-123456"),
Person("Sarah", "Munich", "+49-777-789123"),
Person("Svyatoslav", "Saint-Petersburg", "+7-999-456789"),
Person("Vasilisa", "Saint-Petersburg", "+7-999-123456"))
val phoneBook = people.associateBy { it.phone }
val cityBook = people.associateBy(Person::phone, Person::city)
val peopleCities = people.groupBy(Person::city, Person::name)
val lastPersonCity = people.associateBy(Person::city, Person::name)
// Result
People: [Person(name=John, city=Boston, phone=+1-888-123456), Person(name=Sarah, city=Munich, phone=+49-777-789123), Person(name=Svyatoslav, city=Saint-Petersburg, phone=+7-999-456789), Person(name=Vasilisa, city=Saint-Petersburg, phone=+7-999-123456)]
Phone book: {+1-888-123456=Person(name=John, city=Boston, phone=+1-888-123456), +49-777-789123=Person(name=Sarah, city=Munich, phone=+49-777-789123), +7-999-456789=Person(name=Svyatoslav, city=Saint-Petersburg, phone=+7-999-456789), +7-999-123456=Person(name=Vasilisa, city=Saint-Petersburg, phone=+7-999-123456)}
City book: {+1-888-123456=Boston, +49-777-789123=Munich, +7-999-456789=Saint-Petersburg, +7-999-123456=Saint-Petersburg}
People living in each city: {Boston=[John], Munich=[Sarah], Saint-Petersburg=[Svyatoslav, Vasilisa]}
Last person living in each city: {Boston=John, Munich=Sarah, Saint-Petersburg=Vasilisa}
- When
partitionis used, the collection returns two lists (Pair<List<T>, List<T>) with elements that match the condition and values that do not.
val numbers = listOf(1, 2, 3, 4, 5) val (evenNumbers, oddNumbers) = numbers.partition { it % 2 == 0 }
flatmapfunctions to combine two collections into one. This is useful when combining corresponding lists in a nested structure into one list.minOrNull,maxOrNullreturn the smallest or largest value in the collection, or null if that value is not found.- When using
mapWithDefault, if there is no value, the length of the given key is returned as defined in the method below. 🍎
val mapWithDefault = map.withDefault { k -> k.length }
- When two collections are combined using
zip,Pairis applied to create one collection.
val A = listOf("a", "b", "c")
val B = listOf(1, 2, 3, 4)
val resultPairs = A zip B
Scope Functions
Nested scoped functions are not recommended.
- You can check for null using
let. When used withvariable?.let{ ... },letand below are executed when the variable is not null. Access objects usingit. run, another scoping function, usesthisto access objects, unlikelet. It is mainly useful when calling methods or properties of an object. It can be used naturally when working in the context of objects.- When accessing only member properties, you can also use
with. applyallows the use of code blocks within objects.
val jake = Person()
val stringDescription = jake.apply {
name = "Jake"
age = 30
about = "Android developer"
}.toString()
alsois used likeapplyand makes it convenient to include additional actions.
val jake = Person("Jake", 30, "Android developer")
.also {
writeCreationLog(it)
}
Delegation
In Kotlin, class delegation patterns are possible using by.
class TomAraya(n:String): SoundBehavior by ScreamBehavior(n)
You can define properties by receiving elements of a Map structure by delegating properties.
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
Kotlin/JS
- Used dynamically at runtime using
dynamic. - Using
JS function, you can use thealertfunction in Kotlin language like in JavaScript or createjson.
val json = js("{}")
json.name = "Jane"
json.hobby = "movies"
println(JSON.stringify(json))
- A function or property declared as
externalmeans that the actual implementation is provided in JavaScript. So in Kotlin there is no need to provide an implementation. - Supports
HTML5 Canvas. - HTML creation is possible.
val result = html {
head {
title { +"HTML encoding with Kotlin" }
}
body {
h1 { +"HTML encoding with Kotlin" }
p {
+"this format can be used as an"
}
}
}
Comments
No comments yet. Be the first!