Kotlin

27 Notes
+ Objects Declarations and Companion Objects - Singleton (May 22, 2019, 10:28 p.m.)

Singleton: When we have just ONE INSTANCE of a class in the whole application. object MySingleton object MySingleton { fun someFunction(...) {...} } And then use it: MySingleton.someFunction(...) ----------------------------------------------------- In java, we define SINGLETON, by using the keyword "static" variables and methods. In Kotlin we use "object" for declaring a class. Contrary to a class, an object can’t have any constructor, but init blocks are allowed if some initialization code is needed. object Customer { var id: Int = -1 // Behaves like STATIC variable init { } fun registerCustomer() { // Behaves like STATIC method } } We don't need to instantiate the class! We call it without creating instance. Customer.id = 27 Customer.registerCustomer() ----------------------------------------------------- Companion Objects are same as "object" but declared within a class. class MyClass { companion object { var count: Int = -1 // Behaves like STATIC variable fun typeOfCustomers(): String { // Behaves like STATIC method return "American" } } } MyClass.count MyClass.typeOfCustomers() -----------------------------------------------------

+ Data class and Super class "Any" (May 22, 2019, 9:07 p.m.)

The purpose of Data class is to deal with Data, not the Objects! --------------------------------------------------------------- var user1 = User("Mohsen", 10) var user2 = User("Mohsen", 10) if (user1 == user2 ) { // returns false (They are not equal). The User class must be defined with "Any" keyword to have these variables equal. } class User(var name: String, var id: Int) { } --------------------------------------------------------------- data class User(var name: String, var id: Int) { } ---------------------------------------------------------------

+ lazy initialization (May 22, 2019, 7:39 p.m.)

// If you don't use the following "pi" variable anywhere in your codes, it is a waste of memory. val pi: Float = 3.14f You should use lazy initialization (lazy lambda function): val pi: Float by lazy { 3.14f } When you use the "pi" variable, it will get initialized. ------------------------------------------------------------ - "Lazy initialization" was designed to prevent unnecessary initialization of objects. - Your variables will not be initialized unless you use it in your code. - It is initialized only once. Next time when you use it, you get the value from cache memory. - It is thread-safe. It is initialized in the thread where it is used for the first time. Other threads can use the same value stored in the cache. - The variable can be var or val. - The variable can be nullable or non-nullable data types.

+ lateinit keyword (May 22, 2019, 7:34 p.m.)

- lateinit used only with mutable data type [ var ] - lateinit used only with non-nullable data type - lateinit values must be initialized before you see it class Country { lateinit var name: String }

+ Null Safe (May 22, 2019, 7:16 p.m.)

We have a lot of null safety operators which help up avoid the NullPointerException: ?. Safe Call Operator ?: Elvis !! Not-null Assertion ?.let { .. } Safe Call with let ------------------------------------------------------------ val name: String = null // We can't do this. val name: String? = null // Now it will accept null values ------------------------------------------------------------ 1- Safe Call (?. ) - Returns the length if "name" is not null else returns NULL - Use it if you don't mind getting NULL value println("The length of name is ${name?.length}") // returns null because it has null value at the top. ------------------------------------------------------------ 2- Safe Call with let ( ?.let ) - It executes the block ONLY IF name is NOT NULL name?.let { println("The length of name is ${name.length}") } ------------------------------------------------------------ 3- Elvis-operator ( ?: ) - When we have nullable reference "name", we can say "if name is not null", use it, otherwise use some non-null value. val len = if (name != null ) name.length else: -1 OR (the above code can be simplified as follow): val len = name?.length ?: -1 ------------------------------------------------------------ 4- Non-null assertion operator ( !! ) // Use it when you are sure the value is NOT Null // Throws NullPointerException if the value is found to be NULL. println("The length of name is ${name!!.length}") ------------------------------------------------------------

+ Predicates: a condition returning TRUE of FALSE (May 22, 2019, 7:05 p.m.)

"all": Do all elements satisfy the predicate/condition? "any": Do any element in the list satisfy the predicate? "count": Total elements that satisfy the predicate "find", "last": Returns the FIRST/LAST element that satisfy predicate --------------------------------------------------------------- val myNumbers = listOf( 2, 3, 4, 6, 23, 90) check1 = myNumbers.all { it > 10 } // or all( { it > 10 } ) // Returns false --------------------------------------------------------------- val check2: Boolean = myNumbers.any( { num -> num > 10 } ) // or { it > 10 } // Returns true --------------------------------------------------------------- val totalCount: Int = myNumbers.count { it > 10 } --------------------------------------------------------------- // Returns the first number that matches the predicate val num: Int? = myNumbers.find { it > 10 } --------------------------------------------------------------- Store lambda function as a variable: val myPredicate = { num: Int -> num > 10 } ---------------------------------------------------------------

+ Filter and Map using Lambdas (May 22, 2019, 6:51 p.m.)

val myNumbers: List<Int> listOf(2, 3, 4, 5, 23, 90) val mySmallNums = myNumbers.filter { it < 10 } // or { num -> num < 10 } for (num in mySmallNums) { println(num) // Will print 2, 3, 4, 5 } -------------------------------------------------------- val mySquareNums = myNumbers.map { it * it } // or { num -> num * num } will return 4, 9, 16, 25, so on.... -------------------------------------------------------- val mySmallSquareNums = myNumbers.filter { it < 10 }.map { it * it } -------------------------------------------------------- var people: List<Person> = listOf<Person>(Person(23, "Mohsen"), Person(30, "Ali")) var names = people.map { p -> p.name } // or { it.name } var names = people.filter { person -> person.name.startsWith("M") }.map { it.name } --------------------------------------------------------

+ Collections - Set and Hash Set (May 22, 2019, 6:41 p.m.)

// "Set" contains unique elements // "HashSet" also contains unique elements but sequence is not guaranteed in output // The "9"s will get unify. It means there will be only ONE 9. var mySet = setOf<Int>( 2, 9, 7, 1, 9, 14, 0, 9 ) // Immutable, Read Only for (element in mySet) { println(element) } ---------------------------------------------------------- var mySet = mutableSetOf<Int>( 2, 9, 7, 1, 9, 14, 0, 9 ) // Mutable Set, Read and Write mySet.remove(14) mySet.add(100) ---------------------------------------------------------- // HashSet, the sequence is not guaranteed in output. var mySet = hashSetOf<Int>( 2, 9, 7, 1, 9, 14, 0, 9 ) // Mutable Set ----------------------------------------------------------

+ Collections - Map and Hash Map (May 22, 2019, 3:11 p.m.)

// Immutable, Fixed Size, Read Only var myMap = mapOf<Int, String>(2 to "Mohsen", 7 to "Mehdi") myMap.put() for (key in myMap.keys) { println(myMap[key]) // myMap.get(key) println("Element at Key: $key = ${myMap.get(key)}") // ${myMap[key]} } --------------------------------------------------------- // Mutable, Read and Write both, No Fixed Size var myMap = HashMap<Int, String>() // You can also use mutableMapOf and hashMapOf myMap.put(4, "Mohsen") myMap.put(7, "Mehdi") myMap.replace(4, "Akbar") OR myMap.put(4, "Akbar") ---------------------------------------------------------

+ Collections - List and ArrayList (May 22, 2019, 2:46 p.m.)

Immutable Collections: Read Only Operations - Immutable List: listOf - Immutable Map: mapOf - Immutable Set: setOf Mutable Collections: Read and Write Both - Mutable List: ArrayList, arrayListOf, mutableListOf - Mutable Map: HashMap, hashMapOf, mutableMapOf - Mutable Set: mutableSetOf, hashSetOf ----------------------------------------------------------- Mutable: var list = mutableListOf<String>("Mohsen", "Alex", "Hadi", "Mehdi") list.add("Ali") list.remove("Alex") list.add(3, "Akbar") list[2] = "Asghar" ------------------------ An array with 5 elements, all values are zero. var myArray = Array<Int>(5) { 0 } // Mutable. Fixed Size. myArray[0] = 32 myArray[3] = 54 println(myArray[3]) for (element in myArray) { println(element) } for (index in 0..myArray.size - 1) { } ----------------------------------------------------------- Immutable: // Fixed Size, Read Only, Immutable var list = listOf<String>("Mohsen", "Alex", "Hadi", "Mehdi") ----------------------------------------------------------- ArrayList is an implementation of the MutableList interface in Kotlin: class ArrayList<E> : MutableList<E>, RandomAccess MutableList should be chosen whenever possible, but ArrayList is a MutableList. So if you're already using ArrayList, there's really no reason to use MutableList instead, especially since you can't actually directly create an instance of it (MutableList is an interface, not a class). In fact, if you look at the mutableListOf() Kotlin extension method: public inline fun <T> mutableListOf(): MutableList<T> = ArrayList() you can see that it just returns an ArrayList of the elements you supplied. -----------------------------------------------------------

+ WITH and APPLY Lambdas (May 22, 2019, 2:44 p.m.)

fun main() { var person = Person() with(person) { // Using "with" you can do the same as "person.name, person.age". It seems to be neater. name = "Mohsen" age = 33 } person.apply { // Using "apply" you can also call the methods. name = "Mohsen" age = 33 }.someMethod() } class Person { var name: String = "" var age: Int = 0 fun someMethod() { println("Some string") } }

+ tailrec - Tail recursive functions (May 18, 2019, 1:30 p.m.)

When a function is marked with the tailrec modifier the compiler optimises out the recursion, leaving behind a fast and efficient loop based version instead.

+ Infix Functions (May 18, 2019, 12:54 p.m.)

Infix Functions can be a Member Function or Extension Function. They have SINGLE parameter. They have prefix of "infix" All Infix functions are extension function, but all extension functions are not Infix functions. Infix function can only have ONE parameter. ----------------------------------------------------------- infix fun Int.greaterValue(number: Int): Int { if (this > number) return this else return number } Then you can use it like this: val x = Int = 6 val greaterVal = x.greaterValue(y) OR val greaterVal = x greaterValue y

+ Extension Functions (May 18, 2019, 12:52 p.m.)

Adds new function to the classes: - Can "add" functions to a class without declaring it. - The new functions added behaves like "static".

+ Functions as Expressions - One line functions (May 18, 2019, 11:54 a.m.)

fun max(a: Int, b: Int): Int = if (a > b) a else b ------------------------------------------------------------------- fun max(a: Int, b: Int): Int = if (a > b) { print("$a is greater") a } else { print("$b is greater") b }

+ Functions and Methods (May 18, 2019, 11:43 a.m.)

fun findArea(length: Int, breadth: Int): Int { return length * breadth } fun findArea(length: Int, breadth: Int): Unit { print(length * breadth) } Unit is same as Void in Java

+ BREAK statement with LABELED FOR Loop (May 18, 2019, 11:39 a.m.)

myLoop@ for (i in 1..3) { for (j in 1..3) { println("$i $j") if (i == 2 && j == 2) break@myLoop } } It will BREAK when reaching to "2 2" : 1 1 1 2 1 3 2 1 2 2

+ do-while (May 18, 2019, 11:37 a.m.)

var i: Int = 1 do { println(i) i++ } while (i <= 10)

+ when (May 18, 2019, 11:31 a.m.)

when (x) { in 1..20 -> println("A message") !in 5..9 -> println("Another message") 2 -> { } 4 -> str = "A string value" else -> { } }

+ Ranges (May 18, 2019, 11:21 a.m.)

val r1 = 1..5 // 1, 2, 3, 4, 5 val r2 = 5 downTo 1 // 5, 4, 3, 2, 1 val r3 = 5 downTo 1 step 2 // 5, 3, 1 var r4 = 'a'..'z' // "a", "b", "c", .... "z" var isPresent = 'c' in r4 var countDown = 10.downTo(1) // 10, 9, 8, .... 1 var moveUp = 1.rangeTo(10 // 1, 2, 3, ..... 10

+ Class and Function Class (May 18, 2019, 11:08 a.m.)

class Person { var name: String = "" } ---------------------------------------------------------- var personObj = Person() personObj.name = "Mohsen" print("My name is ${personObje.name}") ---------------------------------------------------------- class Student constructor(name: String) { init { println("The student name is $name") } } You can also drop the constructor: class Student(name: String) { init { println("The student name is $name") } // Secondary constructor constructor(name: String, id: Int): this(name) { // The body of the secondary constructor is called after the init block } constructor(my_name: String, var id: Int): this(my_name) { // var is not allowed here. // You should do the following instead of putting var at the parameters: this.id = id } } ---------------------------------------------------------- By default all classes are "public" and "final" which means you can not inherit from a class. public final class Student { public final name: String = "" } You can drop "public final" keywords. ---------------------------------------------------------- For inheritance you need to make a class "open". open class Human { } class Student: Human() { } ---------------------------------------------------------- Overriding: open class Animal { open fun eat() { println("Animal Eating") } } class Dog: Animal() { override fun eat() { println("Dog is eating") } override fun eat() { super.eat() // Better to use the next line, if used interfaces at the class definition. super<Animal>.eat() print("Dog is eating") } } ---------------------------------------------------------- Visibility Modifiers: public // This is the default protected internal private open class Person { private val = 1 protected val b = 2 internal val c = 3 val d = 10 // public by default } class Indian: Person() { // a is not visible // b, c, d are visible } ----------------------------------------------------------

+ Variables and Data Types (May 18, 2019, 11:04 a.m.)

var age = 33 // Int var grade = 21.5 // Float var myName: String // Mutable String myName = "Mohsen" myName = "MohseNN" val myFamilyName = "Hassani" // Immutable String var gender: Char = 'M' var percentage: Double = 90.78 var marks: Float = 97.4F var isStudying: Boolean = true

+ Static Members for class (May 17, 2019, 10:33 a.m.)

Most of the programming language have concepts where classes can have static members — fields that are only created once per class and can be accessed without an instance of their containing class. Kotlin doesn’t have static member for class, it means that you can’t create static method and static variable in Kotlin class. Fortunately, Kotlin object can handle this. If you declare a companion object inside your class, you'll be able to call its members with the same syntax as calling static methods in Java/C#, using only the class name as a qualifier. class MyClass { companion object { val info = "This is info" fun getMoreInfo():String { return "This is more fun" } } } MyClass.info // This is info MyClass.getMoreInfo() // This is more fun Note that, even though the members of companion objects look like static members in other languages, at runtime those are still instance members of real objects, and can, for example, implement interfaces.

+ for Loop / Iteration (May 10, 2019, 9:52 a.m.)

for (item in collection) { // body of loop } ------------------------------------------------------------- Iterate Through a Range: fun main(args: Array<String>) { for (i in 1..5) { println(i) } } ------------------------------------------------------------- If the body of the loop contains only one statement (like above example), it's not necessary to use curly braces { }. fun main(args: Array<String>) { for (i in 1..5) println(i) } ------------------------------------------------------------- for (i in 1..5) print(i) for (i in 5 downTo 1) print(i) for (i in 1..5 step 2) print(i) for (i in 5 downTo 1 step 2) print(i) ------------------------------------------------------------- Iterating Through an Array: var language = arrayOf("Ruby", "Koltin", "Python" "Java") for (item in language) println(item) ------------------------------------------------------------- Iterate through an array with an index: var language = arrayOf("Ruby", "Koltin", "Python", "Java") for (item in language.indices) { // printing array elements having even index only if (item%2 == 0) println(language[item]) } ------------------------------------------------------------- Iterating Through a String: var text= "Kotlin" for (letter in text) { println(letter) } ------------------------------------------------------------- -------------------------------------------------------------

+ List (May 10, 2019, 9:11 a.m.)

List is by default immutable and mutable version of Lists is called MutableList! val list: List<String> = ArrayList() In this case you will not get an add() method as list is immutable. ----------------------------------------------------------------- val list: MutableList<String> = ArrayList() Now you will see an add() method and you can add elements to list. ----------------------------------------------------------------- MUTABLE collection: val list = mutableListOf(1, 2, 3) list += 4 ----------------------------------------------------------------- IMMUTABLE collection: var list = listOf(1, 2, 3) list += 4 -----------------------------------------------------------------

+ Getters and setters (May 9, 2019, 2:38 a.m.)

If you are calling var side: Int = square.a it does not mean that you are accessing a directly. It is same as: int side = square.getA(); in Java, cause Kotlin autogenerates default getters and setters. In Kotlin, only if you have special setter or getter you should specify it. Otherwise, Kotlin autogenerates it for you.

+ Null Operators ? !! (May 9, 2019, 2:06 a.m.)

What is the meaning of ? in savedInstanceState: Bundle? ? It means that savedInstanceState parameter can be Bundle type or null. Kotlin is null safety language. var a : String // you will get a compilation error, cause a must be initialized and it cannot be null. That means you have to write: var a : String = "Init value" Also, you will get a compilation error if you do: a = null To make a nullable, you have to write: var a : String? Let’s say that we have nullable nameTextView. The following code will give us NPE if it is null: nameTextView.setEnabled(true) Kotlin will not allow us to even do such a thing. It will force us to use ? or !! operator. If we use ? operator: nameTextView?.setEnabled(true) the line will be proceeded only if nameTextView is not a null. In another case, if we use !! operator: nameTextView!!.setEnabled(true) it will give us NPE if nameTextView is a null. It is just for adventurers. lateinit modifier allows us to have non-null variables waiting for initialization.