Kotlin Crash course

 Kotlin

var greeting: String = "Hi"

val name: String = "Malathi"

we can reassign value to variable defined using var but not val. By default Strings in Kotlin are non null values. To make them nullable, we should use ? operand like below

val name: String? = "Malathi"

Ex:

fun main() {

   var greeting: String = "Hi"

   val name: String = "Malathi"

   println(greeting)

   println(name)

}

Kotlin has type inference. It means that the type is automatically detected based on the value assigned to the variable. So var greeting = "Hi" statement too works.

Control loops

if statement: if(greeting != null) { println("if statement")}

while statement: It is similar to Switch statement in Java

while(greeting) {

   null -> println("Hi")

   else -> println(greeting)

val greetingToInvite = if(greeting != null) greeting else "Hi"

println(greetingToInvite)

val greetingToInvite = when(greeting) { 

  null -> "Hi"

  else -> greeting

}

Basic Functions

fun getGreeting(): String {return "Hello"}

fun getGreeting() = "Hello" This is single expressions function with type inference.

fun getGreeting(itemToGreet: String) { println("Hello $itemToGreet")} This is called Stirng template

fun getGreeting(itemToGreet: String) = println("Hello $itemToGreet") This is called Stirng template

fun getGreeting(itemToGreet: String)

Collections and Iterations

Arrays:

val interestingThings = arrayOf("1", "2")

interestingThings[0] or interestingThings.get(0)

for(thing in interestingThings) {println(thing)}

interestingThings.forEach{it -> println(it)}

List

val interestingThings = listOf("1", "2")

for(thing in interestingThings) {println(thing)}

Map

val map = mapOf(1 to "a", 2 to "b", 3 to "c")
map.forEach { key, value -> println("$key $value")}

By default Collections are immutable. If we want to make them mutable ...
val things = mutableListOf("1", "2")
val map = mutableMapOf(1 to "a", 2 to "b", 3 to "c")

Pass list to a method:

fun listFun(greeting: String, itemsToGreet: List<String>) {
    itemsToGreet.forEach(it -> {println("$greeting $it")})
}

fun listFun(greeting: String, vararg itemsToGreet: List<String>) {
    itemsToGreet.forEach(it -> {println("$greeting $it")})
}  

fun main() {
   listFun("Hi", "Lisa", "Mona")
   val interestingThings = arrayOf("one", "two", "three")
   listFun("Hi", *interestingThings)
}

Named arguments

fun greetPerson(name: String, greeting: String) = println("$greeting $name)
fun main() {
    greetPerson(name = "Malathi", greeting = "Hello")
    greetPerson(greeting = "Hello", name = "Neelima")
}

Classes

class Person(_firstName: String, _lastName: String) {
    val firstName: String
    val lastName: String
    init {
       _firstName = firstName
       _lastName = lastName
    }
}

class Person(_firstName: String, _lastName: String) {
    val firstName: String = _firstName
    val lastName: String = _lastName
}
class Person(val firstName: String, val lastName: String)

class Person(val firstName: String, val lastName: String) {
      var nickName: String? = null
            set(value) {
               field = value
               println($value)
            } 
            get() {
               println($field) return field}

      fun printNickName() { println($nickName)}

Elvis operator: Instead of long and verbose if/else syntax to check null we can use this operator.
val nickNameToPrint = if(nickName != null) nickName else "no nickname"
we can redo this as val nickNameToPrint = nickName?: "no nickname" 

Visibility modifiers: All classes, functions and properties are public by default. We can make them internal (accessible within the module), private and protected.

Interfaces

interface PersonInfoProvider {
    fun printInfo(person: Person)

class BasicInfoProvider : PersonInfoProvider {
    override fun printInfo(person : Person) {
        println("printInfo")
    }
}

fun main() {
   val provider = BasicInfoProvider()
provider.printInfo(Person())
}

We can Add default methods and properties to interfaces. properties can be overriden by classes.

interface PersonInfoProvider {
   val providerInfo : String // We can not assign a value in interfaces.
    fun printInfo(person : Person) {
        println(providerInfo)
        println("printInfo")
    }
interface SessionInfoProvider {
   fun getSessionId() : String
}

class BasicInfoProvider : PersonInfoProvider, SessionInfoProvider  {
   override val providerInfo: String
          get() = "BasicInfoProvider"
    override fun getSessionId() : String {
        println("Calling SessionInfoProvider")
    }
}

fun main() {
   val provider = BasicInfoProvider()
   provider.printInfo(Person())
}
}

Inheritance

By default classes in Kotlin are not open to inherit into another class. To do that we should explicitly declare base class with open keyword.

open class BasicInfoProvider : PersonInfoProvider, SessionInfoProvider  {
   override val providerInfo: String
          get() = "BasicInfoProvider"
    override fun getSessionId() : String {
        println("Calling SessionInfoProvider")
    }
}

class FancyInfoProvider : BasicInfoProvider() {
    override val providerInfo : String 
         get() = "Fancy Info Provider"

    override fun printInfo(person: Person) {
         super.printlnInfo(person)
         println("Fancy info")
    }
}
 
Object Expressions

An object expression allows you to create an anonymous inner class so that you don't have to create a new named class.

fun main() {
    val provider = object :  PersonInfoProvider {
       override val providerInfo : String 
            get() = "New info provider"
 
       fun getSessionId() = "id"
    }
}

Companion objects

It is scoped to an instance of another class. companion objects can also implement interfaces.

class Entity private constructor(val id: String) {

companion object Factory {
     fun create() = Entity("id")
}

fun main() {
   val entity = Entity.Factory.create()
}

Object Declarations: is the convenient way of creating thread safe singletons within Kotlin.

class Entity (val id: String, val name: String) {
     override fun toString(): String {
         return "$id, $name"
     }
}
object EntityFactory {
     fun create() = Entity("id", "name")
}

fun main() {
   val entity = Entity.Factory.create()
}

Enum Classes

enum class EntityType {
   EASY, MEDIUM, HARD
}

Sealed Classes: Allow us to define restricted class hierarchies. We can define set number of classes all extending base type but those are the only classes which can extend the base type.

sealed class Entity {
   data class Easy(val id: Stirng, val name: String) : Entity()
   data class Medium(val id: Stirng, val name: String) : Entity()
   data class Hard(val id: String, val name: String, val multipliers: Float) : Entity()
}
 
Data classes are Kotlin's way of providing very concise and immutable data types. They have toString and equals and hashcode methods to compare instances of data classes. These classes allows us to represent data in applications and then compare the data no matter where it comes from.

data classes give copy method where we could copy the data of one instance to another.
We use === to check referential quality and then == to check the data equality.

Extension Functions or extention properties

Advanced Functions








Comments

Popular posts from this blog

Bash - Execute Pl/Sql script from Shell script

How to get client Ip Address using Java HttpServletRequest

How to install Portable JDK in Windows without Admin rights