A collection of random and frequently used idioms in Kotlin.
data class Customer(val name: String, val email: String)
POJO - Plain Old Java Object
POCO - Plain Old CLR(Common Language Runtime) Object
These terms are used to describe simple, lightweight classes that are used to represent data in an application.
Theses methods are automatically generated.
val customer = Customer("John", "john@example.com")
val (name, email) = customer
fun foo(a: Int = 0, b: String = "") { ... }
val positives = list.filter { x -> x > 0 }
val positives = list.filter { it > 0 }
if ("john@example.com" in emailsList) { ... }
if ("jane@example.com" !in emailsList) { ... }
println("Name $name")
when (x) {
is Foo -> ...
is Bar -> ...
else -> ...
}
val list = listOf("a", "b", "c")
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
// Access
println(map["key"])
map["key"] = value
// Traverse
for ((k, v) in map) {
println("$k -> $v")
}
// closed range: includes 100
for (i in 1..100) { ... }
// half-open range: does not include 100
for (i in 1 until 100) { ... }
for (x in 2..10 step 2) { ... }
for (x in 10 downTo 1) { ... }
(1..10).forEach { ... }
// the value is computed only on first access
val p: String by lazy {
// compute the string
}
fun String.spaceToCamelCase() { ... }
"Convert this to camelcase".spaceToCamelCase()
object Resource {
val name = "Name"
}
In kotlin, 'object' declares a sigleton which is a class that can have only one instance.
abstract class MyAbstractClass {
abstract fun doSomething()
abstract fun sleep()
}
fun main() {
val myObject = object : MyAbstractClass() {
override fun doSomething() {
// ...
}
override fun sleep() { // ...
}
}
myObject.doSomething()
}
val files = File("Test").listFiles()
println(files?.size)
// size is printed if files is not null
//If-not-null-else
println(files?.size ?: "empty")
// if files is null, this prints "empty"
// To calculate the fallback value in a code block, use `run`
val filesSize = files?.size ?: run {
return someSize
}
println(filesSize)
'?.'- safe call operator : if the value on the left is null, this expression returns null.
'?:' - Elvis operator : if the value on the left is null, this expression provides an alternative value.
val values = ...
val email = values["email"] ?: throw IllegalStateException("Email is missing!")
val emails = ... // might be empty
val mainEmail = emails.firstOrNull() ?: ""
val value = ...
value?.let {
... // execute this block if not null
}
val value = ...
val mapped = value?.let { transformValue(it) } ?: defaultValue
// defaultValue is returned if the value or the transform result is null.
fun transform(color: String): Int {
return when (color) {
"Red" -> 0
"Green" -> 1
"Blue" -> 2
else -> throw IllegalArgumentException("Invalid color param value")
}
}
fun test() {
val result = try {
count()
} catch (e: ArithmeticException) {
throw IllegalStateException(e)
}
// Working with result
}
val y = if (x == 1) {
"one"
} else if (x == 2) {
"two"
} else {
"other"
}
// when is also possible
val y = when (x) {
1 -> "one"
2 -> "two"
else -> "other"
}
fun arrayOfMinusOnes(size: Int): IntArray {
return IntArray(size).apply { fill(-1) }
}
'apply' function is a useful tool for creating builder-style APIs that allow chaining of method calls, even if the methods return 'Unit'.
val myArray = arrayOfMinusOnes(5)
Like this, myArray is created by just a single expression.
fun theAnswer() = 42
// this is equivalent to
fun theAnswer(): Int {
return 42
}
//or like this
val y = when (x) {
1 -> "one"
2 -> "two"
else -> "other"
}
class Turtle {
fun penDown()
fun penUp()
fun turn(degrees: Double)
fun forward(pixels: Double)
}
val myTurtle = Turtle()
with(myTurtle) { //draw a 100 pix square
penDown()
for (i in 1..4) {
forward(100.0)
turn(90.0)
}
penUp()
}
val stream = Files.newInputStream(Paths.get("/some/file.txt"))
stream.buffered().reader().use { reader ->
println(reader.readText())
}
The try-with-resources feature introduced in Java 7 allows you to write more concise and robust code when dealing with resources.
'use' function creates new scope and the input stream is automatically closed when the scope is exited.
Within 'use', stream -> buffered stream with 'bueffered()' and buffered -> reader with 'reader()'. And it is passed to a lamda expression which uses readText().
The use function ensures that the input stream and the reader are closed after the lambda expression is executed, even if an exception is thrown.
// public final class Gson {
// ...
// public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
// ...
inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java)
//for ex
val json = "{\"name\": \"John\", \"age\": 30}"
val gson = Gson()
val person = gson.fromJson<Person>(json)
val b: Boolean? = ...
if (b == true) {
...
} else {
// `b` is false or null
}
var a = 1
var b = 2
a = b.also { b = a }
'also' is simmilar to 'apply'.
Diff is that 'also' returns the object itself, while 'apply' returns the result of the lamda expression.
fun calcTaxes(): BigDecimal = TODO("Waiting for feedback from accounting")
Kotlin's standard library has a TODO() function that will always throw a NotImplementedError