02 - Kotlin
Variables
Variable (mutable) - var xxx
Constant (immutable) – val yyy
Primary Constructor
The primary constructor is part of the class header
class Person(val _firstName: String, val _lastName: String, var _age: Int) {
fun info(){
print("$_firstName $_lastName $_age")
}
}
Initializer block(s)
The primary constructor has a constrained syntax, and cannot contain any code.
Initializer blocks are used for class setup
class Person(var _firstName: String, var _lastName: String, val _age: Int) {
init {
_firstName = _firstName.capitalize()
}
fun info(){
print("$_firstName $_lastName $_age")
}
}
Secondary Constructor
Must not overload primary (different signature)
Must call primary constructor (if primary is defined)
class Person(var _firstName: String, var _lastName: String, val _age: Int) {
init {
_firstName = _firstName.capitalize()
}
fun info(){
print("$_firstName $_lastName $_age")
}
// must call primary constructor
constructor(_firstName1: String, _lastName1: String) : this(_firstName1, _lastName1, 99) {
}
}
Companion Object
Companion objects are singleton objects whose properties and functions are tied to a class but not to the instance of that class
Use @JvmStatic annotation to get true static bytecode in jvm
class Drink {
companion object {
const val WATER = "water"
}
fun bestDrink() = WATER
}
class X {
init {
val a = Drink.Companion.WATER
val b = Drink.WATER
val c = Drink().bestDrink()
}
}
Nullable ref
var b: String?
Vsvar a: String
val l = if (b != null) b.length else -1
- Safe calls with ?.
print(b?.length)
b?.let { print(it) }
- Elvis operator -
val l = b?.length ?: -1
val l = b!!.length
- not-null assertion- Safe casts
val aInt: Int? = a as? Int
Scoping functions
Executing block of code within the context of object. Call scoping function on object providing lambda expression - temporary scope is formed. In this scope you can access the object without its name.
Scope functions are
- let
let
takes the object it is invoked upon as the parameter (it
) and returns the result of the lambda expression.
fun scopeLet(){
var str ="This is test"
var strLen = str.let { it.length }
strLen++
var str2: String? = null
var strLen2 = str2?.let {
it.length
} ?: 0
}
- run
Similar to the let function, the run function also returns the last statement.
Unlike let, the run function doesn’t support the it
keyword.
The context object is available as a receiver (this
).
fun scopeRun() {
var name = "nothing here!"
name = run {
"RUN"
}
print(name) // RUN
}
- with
A non-extension function: the context object is passed as an argument, but inside the lambda, it's available as a receiver (this
). The return value is the lambda result.
with is used to change instance properties without the need to call dot operator over the reference every time.
The last expression of with function returns a result.
fun scopeWith() {
data class Person(var name: String, var tutorial: String)
var person = Person("Anupam", "Kotlin")
var xyz = with(person) {
name = "No Name"
tutorial = "Swift"
val xyz = "return value"
xyz
}
println(xyz)
}
- apply
Unlike let
, it returns the original object instead of any new return data. Hence the return data has always the same type.
Runs on the object reference (receiver) in the expression and returns the object reference on completion.
fun scopeApply() {
data class Person(var name: String, var tutorial: String)
var person = Person("akaver", "Kotlin")
person.apply {
this.tutorial = "Swift"
}
println(person)
}
- also
also
expressions does some additional processing on the object it was invoked.
Unlike let
, it returns the original object instead of any new return data. Hence the return data has always the same type.
Like let
, also uses it
too.
fun scopeAlso(){
var m = 1
m = m.also { it + 1 }.also { it + 1 }
println(m) // 1
}
Scope functions, overview
- Executing a lambda on non-null objects: let
- Introducing an expression as a variable in local scope: let
- Object configuration: apply
- Object configuration and computing the result: run
- Running statements where an expression is required: non-extension run
- Additional effects: also
- Grouping function calls on an object: with
takeIf, takeUnless
In addition to scope functions, the standard library contains the functions takeIf and takeUnless. These functions let you embed checks of the object state in call chains.
fun takeIf() {
var number = 2
val evenOrNull = number.takeIf { it % 2 == 0 }
}
Returns null on negative/other case