Kotlin Notes

Important Notes & Links


Readhttps://www.programiz.com/kotlin-programming/hello-world


Kotlin is a strongly statically typed language.

Just like C++ and Java , Kotlin also has a main( ) function.

There are many useful 'Keyword operators' in Kotlin like "is" , "as", "in" , "when"  etc.

The Top-most class in Kotlin (just like Object class in java ) is "Any" class , every class inherits from it.


main() vs main(args : Array<String>)

In later versions of kotlin it is not necessary to pass the string array as the parameter to the main function,but mostly it is passed to make the code run on all versions of kotlin.

fun main() {

print("Hello world !")
}


fun main(args:Array<String>) {

print("Hello world !")
}


-------------------------------------------------------------------------------------------------------------------------


Hello World Program


Test.kt


fun main(args : Array<String>){
println("Hello world !!")
}


Unlike Java, it is not mandatory to create a class in every Kotlin program. It's because the Kotlin compiler creates the class for us.


-------------------------------------------------------------------------------------------------------------------------


Variables


To declare a variable in Kotlin, either var or val keyword is used.

  • val (Immutable reference) - The variable declared using val keyword cannot be changed once the value is assigned. It is similar to final variable in Java.
  • var (Mutable reference) - The variable declared using var keyword can be changed later in the program. It corresponds to regular Java variable.



fun main(args : Array<String>){

val score=101
score=201 // ERROR

var score2 = 101
score2 = 201

}


We can specify the variable "Type" explicitly too , but it is not necessary.


fun main(args : Array<String>){

var name:String = "Deepesh"

var surname = "Mhatre"

//We can explicitly specify the
// Type of variable , however
// it is not neccessary.

}


Kotlin built in data type are categorized as following different categories : 

  • Number
  • Character
  • Boolean
  • Array
  • String



fun main(args : Array<String>){

// SOME COMMON DATA TYPES.

var number: Int = 101

var string_value : String = "It's a string"

var double_value : Double= 99.999

var char_value : Char = 'k' // use single quotes only.

var bool_value : Boolean = true

}



Type conversion


Here's a list of functions in Kotlin used for type conversion:

Note, there is no conversion for Boolean types.



fun main(args : Array<String>){

var score:Int = 101
var newScore: String = score.toString()

println(newScore)

}


The functions mentioned above can be used in both directions (conversion from larger to smaller type and conversion from smaller to larger type).

However, conversion from larger to smaller type may "truncate" or Change the value so be Careful there.


'lateinit' in kotlin


lateinit means late initialization. 

If you do not want to initialize a variable, instead you want to initialize it later, then declare that variable with lateinit keyword.



fun main(args:Array<String>) {

lateinit var name:String

name = "This is a string"

}


-------------------------------------------------------------------------------------------------------------------------


Null Values & Elvis Operator


By default , types in kotlin won't accept null values.

If you want a variable to hold null value , you must explicitly declare that it's type is "nullable" , to do this we use the Elvis Operator (?)


To declare a variable nullable , put the elvis operator after its data type.


fun main() {

var name1 : String= null // ERROR

var name2 : String? = null

}



-------------------------------------------------------------------------------------------------------------------------


Arrays in Kotlin


Array in Kotlinis mutable in nature with fixed size which means we can perform both read and write operations on elements of array.


We can use the library function arrayOf() to create an array by passing the values of the elements to the function.


fun main(args : Array<String>) {

val Scores = arrayOf(1, 2, 3, 4) //implicit type declaration

val newScores = arrayOf<Int>(1, 2, 3,4) //explicit type declaration

println(Scores[1])
print(newScores[3])

}

//OUTPUT
//2
//4



Kotlin also has some built-in factory methods to create arrays of primitive data types, such as byteArray, intArray, shortArray, etc



fun main(args : Array<String>) {

val num = intArrayOf(1, 2, 3, 4)

val letters = charArrayOf('a','b','c','d')


}


Other factory methods available for creating arrays:

  • byteArrayOf()
  • charArrayOf()
  • shortArrayOf()
  • longArrayOf()


Acessing & Modifying Arrays



fun main(args: Array<String>) {

val num = arrayOf(1, 2, 3, 4, 5, 6, 7)

// GETTING VALUES
println(num[0])
println(num.get(0))

// SETTING VALUES
num[0]= 2
num.set(0,2)

}


-------------------------------------------------------------------------------------------------------------------------


Input / Output in Kotlin


You can use println() and print() functions to send output to the standard output (screen).

print() - prints string inside the quotes.

println() - prints string inside the quotes similar like print() function. then the cursor moves to the beginning of the next line.



fun main(args : Array<String>){

print("My name is : ")
print("Deepesh" + "\n")

println("My surname is : ")
print("Mhatre")

}

//OUTPUT
//My name is : Deepesh
//My surname is :
//Mhatre



There are 2 ways to take input in Kotlin :


1] use the "readline()" method.



fun main(args : Array<String>){

print("Enter your age : ")

//To read a line of string in Kotlin, you can use readline() function.
var age:String= readLine().toString()

print("Welcome , " + age)

}




2] use "Scanner" object from Java.


import java.util.Scanner

fun main(args: Array<String>) {

// Creates an Scanner object
val reader = Scanner(System.`in`)
print("Enter a number: ")

// nextInt() reads the next integer from the keyboard
var integer:Int = reader.nextInt()

println("You entered: $integer")
}


To get LongFloatdouble and Boolean input from the user, you can use nextLong()nextFloat()nextDouble() and nextBoolean() methods respectively.


-----------------------------------------------------------------------------------------------------------------------


If...else statement



fun main(args: Array<String>) {

var score = 100

if (score > 100) {
print("Score greater than 100 !")
} else if (score < 100) {
print("Score less than 100 !")
} else {
print("Score is equal to 100 !")
}

}


Unlike Java (and other many programming languages), if can be used an expression in Kotlin; it returns a value.



fun main(args: Array<String>) {

var score = 100

val result = if (score > 100) {
"Score greater than 100 !"
} else if (score < 100) {
"Score less than 100 !"
} else {
"Score is equal to 100 !"
}

print(result) // Score is equal to 100 !

}



fun main(args: Array<String>) {

var score = 100

val result = if (score > 100) "Score greater than 100 !" else "Score is equal to 100 !"

print(result) // Score is equal to 100 !

}

// The curly braces are optional if the body of if has only one statement.
// This is similar to ternary operator in Java



While Loop


syntax :

while (testExpression) {
    // codes inside body of while loop
}



fun main(args: Array<String>) {

var num = 10

while (num > 0){
println("Value : " + num)
num--
}

}




Do...While Loop


The do...while loop is similar to while loop with one key difference. The body of do...while loop is executed once before the test expression is checked.


syntax :

do {
   // codes inside body of do while loop
} while (testExpression);



For Loop


syntax :

for (item in collection) {
    // body of loop
}



fun main(args: Array<String>) {

for (i in 1..5) {
println(i)
}
}




Switch in Kotlin


The when construct in Kotlin can be thought of as a replacement for Java switch Statement.



fun main() {
val number = 4

when(number) {
1 -> print("One")
2 -> print("Two")
3 -> print("Three")
4 -> print("Four")
5 -> print("Five")
else -> print("invalid number")
}

}


-----------------------------------------------------------------------------------------------------------------------


Functions in Kotlin


To define a function in Kotlin, 'fun' keyword is used.


syntax :

fun functionName() : ReturnType {
    // function body
}



// If you are returning a value , you have to define a "Return Type".
fun AddNumbers(num1:Int , num2:Int): Int {
return num1+num2
}

fun printName(name:String){
print(name)
}

fun main(args: Array<String>) {

print(AddNumbers(10,20))
print("\n" + printName("Deepesh"))
}



-------------------------------------------------------------------------------------------------------------------------


Lambda / Anonymous Functions


Lambdas are functions with no name , they can take parameters , execute a expression & return the value.

A Lambda expression starts and ends with curly brackets. We use "->" to separate parameters from the body. To use a lambda , use the "invoke()" method.


syntax :

{parameters -> body}



val addInts = {num1:Int,num2:Int -> num1+num2}

fun main() {

val result1 = addInts.invoke(10,20)

// This does the same thing.
val result2 = addInts(10,20)

println(result1) // 30
println(result2)

}


-------------------------------------------------------------------------------------------------------------------------

watch : Click here


Scope Functions


Kotlin contains several functions whose sole purpose is to execute a block of code within the context of an object. When you call such a function on an object , it forms a temporary scope. 

In this scope, you can access the object without its name. Such functions are called scope functions.

The context of the object can be referred to as “it” or this which we will be understanding through examples in this article.

There are five of them: letrunwithapplyalso.


These 5 scope functions can be differentiated based on 2 things : 

1] The way they refer to context object ("it" or "this").

2] The return value (Either lambda result or Context object) 


Context object means the thing , you use to refer to the object inside the scope/lambda.

Lambda result means the expression on the last line of the lambda.

Context object means the object itself on which we are operating.


1] with

Context Object : this

Return value : lambda result.

This function takes 1 parameter which is the object on which you want to operate. 

We can acess the object inside the lambda using the Context object i.e 'this'.



class Person{

var name:String?=null
var surname:String?=null
var age:Int?=null

fun printInfo(){
println("Name is $name $surname, and the age is $age")
}
}

fun main(args: Array<String>) {

val p1 = Person()

// Without using "With" function.
p1.name="Deepesh"
p1.surname="Mhatre"
p1.printInfo()

// Using "With" function.
val result :String= with(p1){
this.name="Rohan"
this.surname="Singh"
this.printInfo()
"This is the return value"
}

print(result)
}

// OUTPUT :
//Name is Deepesh Mhatre, and the age is null
//Name is Rohan Singh, and the age is null
//This is the return value


2] apply

Context Object : this

Return value : Context Object.



class Person{

var name:String?=null
var surname:String?=null
var age:Int?=null

fun printInfo(){
println("Name is $name $surname, and the age is $age")
}
}

fun main(args: Array<String>) {


// Traditional object initialisation.
val p1 = Person()
p1.name="Deepesh"
p1.surname="Mhatre"
p1.age=18


// Object Initialisation using 'apply'
val p2 : Person = Person().apply {
this.name="Rohan"
this.surname="Singh"
this.age=18
}
// Creates a person object, operates on it & then return it.

}



3] also

Context Object : it

Return value : Context Object.

This function is used when we want to perform additional operations on a object after we have initialised it.



class Person(var name:String,var surname:String,var age:Int){

fun printInfo(){
println("Name is $name $surname, and the age is $age")
}
}

fun main(args: Array<String>) {

var p1 : Person = Person("Deepesh","Mhatre",18)

p1.also {
it.name="Rohan"
it.surname="Singh"
}

}



4] let

Context Object : it

Return value : Lambda result.

Generally we use 'let' function to avoid 'nullpointerexception'.

Along with 'let' we also need to use the safe-call operator (?).



// Not using 'let' function.
fun main(args: Array<String>) {

val name:String? = null

print(name.capitalize())

// Gives 'nullpointer exception'.

}


// Using 'let' function.
fun main(args: Array<String>) {

val name:String? = null

// The 'let' function executes this code only if name!=null
name?.let {
print(it.capitalize())
}

}


4] run

Context Object : this

Return value : Lambda result.

If you want to operate on a nullable object and at the sametime avoid NullPointerException , use the 'run' function.

Along with 'run' we also need to use the safe-call operator (?).



class Person(var name: String, var surname: String, var age: Int) {

fun printInfo() {
println("Name is $name $surname, and the age is $age")
}
}

fun main(args: Array<String>) {

val p1: Person? = null

// Gets executed only if p1!=null
p1?.run {
print(this.name)
print(this.surname)

"Code executed !"
}

}



-----------------------------------------------------------------------------------------------------------------------


Classes and Objects


To define a class in Kotlin, class keyword is used.



class Animal{

var name=null

fun makeSound(){
print("Animal is making sound ! ")
}
}


fun main(args: Array<String>) {

// Creating Object
val Tiger = Animal()
Tiger.makeSound()

}



Acess Modifers


Just like Java , Kotlin also has some important Acess Modifers that control the acess level of Classes, objects, properties, methods , constructors etc.


  • private - visible (can be accessed) from inside the class only.
  • public - visible everywhere.
  • protected - visible to the class and its subclass.
  • internal - any client inside the module can access them.


NOTE: If you do not specify the visibility modifier, it will be public by default.


Constructors


In Kotlin, there are 2 constructors:

1] Primary constructor.


The primary constructor is part of the class header. 

Here's an example:

class Person(val firstName: String, var age: Int) {
    // class body
}

The block of code surrounded by parentheses is the primary constructor: (val firstName: String, var age: Int).

The constructor declared two properties: firstName  and age.



class Person(var name:String , var age:Int){

// You can still add methods and attributes here.
}


fun main(args: Array<String>) {

val person1 = Person("Deepesh",18)
print("Name : " + person1.name + " Age : " + person1.age)

}

// OUTPUT - Name : Deepesh Age : 18




Initializer Blocks


The primary constructor has a constrained syntax, and cannot contain any code.

To put the initilization code , initializer block is used.

 It is prefixed with init keyword.


class Person(fName: String, personAge: Int) {
val firstName: String
var age: Int

// initializer block.
// It is executed with constructor everytime you create object.
init {
firstName = fName.capitalize()
age = personAge

println("First Name = $firstName")
println("Age = $age")
}
}

fun main(args: Array<String>) {
val person1 = Person("joe", 25)
}






2] Secondary constructor.


 A class can also contain one or more secondary constructors. They are created using constructor keyword.



// Secondary constructors are useful in Constructor overloading.

class Person{

var name=""
var surname=""
var age=0

constructor(_name:String,_surname:String){
name=_name
surname=_surname
}

constructor(_name:String,_surname:String,_age:Int){
name=_name
surname=_surname
}

}


fun main(args: Array<String>) {

var p1 = Person("Deepesh","Mhatre")

var p2 = Person("Rohan","Sigh",18)

}


------------------------------------------------------------------------------------------------------------------------


Inheritance


By default, classes in Kotlin are 'final'. If you are familiar with Java, you know that a final class cannot be subclassed.

By using the 'open' keyword on a class, compiler allows you to derive new classes from it.



//NOTE :
// If you want to override attributes & methods of superclass declare
// them as "open" in superclass and then use the "override" keyword
// in the subclass to override them

open class Animal {

open lateinit var name:String

open fun makeSound(){
println("Animal makes sound !")
}

open fun eatFood(){
println("Animal is eating food !")
}

}

// Inherits Animal class
class Tiger : Animal() {

override var name= "Tiger"

override fun makeSound() {
println("Roarrrr !!")
}

override fun eatFood() {
println("Tiger is eating !")
}

}


fun main(args : Array<String>) {

val tiger = Tiger()
tiger.makeSound() // Roarrrr !!

}


-------------------------------------------------------------------------------------------------------------------------


Abstract Class


An abstract class cannot be instantiated (you cannot create objects of an abstract class). However, we can create object of its subclasses.

Properties and Methods of an abstract class are non-abstract unless you explictly use abstract keyword to make them abstract. 

Abstract Properties & Methods dont have a body & their implementation  is provided by subclasses.



abstract class Animal{

abstract var name:String
abstract fun makeSound()

}

class Tiger : Animal(){

override var name: String="Tiger"

override fun makeSound() {
println("Roarrrrr !")
}
}

fun main() {

val tiger = Tiger()
tiger.makeSound()
}


-------------------------------------------------------------------------------------------------------------------------


Interface in Kotlin


Kotlin interfaces are similar to interfaces in Java. They can contain definitions of abstract methods as well as implementations of non-abstract methods.

Abstract classes in Kotlin are similar to interface with one important difference. It's not mandatory for properties/methods of an abstract class to be abstract.


Keyword interface is used to define interfaces in Kotlin.




interface Superpowers{

fun fly() // If you dont provide body, it automatically becomes abstract.

fun invisibility(){
println("I am invisible , see !")
}

}

// Implement interface
class Person : Superpowers{
override fun fly() {
println("I can fly !")
}

}

fun main() {

val p1 = Person()
p1.fly()
p1.invisibility()

}


Note : A class can inherit only from one other class , but it can implement multiple interfaces.


One Interface can also inherit from another Interface.


interface GodPowers{

fun Timetravel(){
println("I can travel in time !")
}

fun Omnipresence(){
println("I am everywhere !")
}

}

// interface implements interface
interface Superpowers : GodPowers{

fun fly() // If you dont provide body, it automatically becomes abstract.

fun invisibility(){
println("I am invisible , see !")
}

}

// Implement interface
class Person : Superpowers{
override fun fly() {
println("I can fly !")
}

}

fun main() {

val p1 = Person()
p1.fly()
p1.invisibility()
p1.Timetravel()

}


-------------------------------------------------------------------------------------------------------------------------


Object Declaration


Singleton is an design pattern where a class can have only one instance (object).

Kotlin provides an easy way to create singletons using the object declaration feature. For that, object keyword is used.



object Person{

lateinit var name:String

fun Eat(){
print("I am eating")
}

}

fun main() {

val p1 = Person() // ERROR

// we cannot create object , since there is already one created,
// the 'object' declaration itself.

val p2= Person.Eat()

}


An object declaration can contain properties, methods and so on. However, they are not allowed to have constructors.

Similar to objects of a normal class, you can call methods and access properties by using the .  (dot) notation.


-------------------------------------------------------------------------------------------------------------------------


Companion Objects


Sometimes we can use the properties/methods inside a class without creating their objects , all we have to do is declare them as "Companion objects".

In Kotlin, you can call class methods directly by using the class name. For that, you need to create a companion object by marking 'object declaration' with companion keyword.



class Person {

companion object {
fun callMe() = println("I'm called.")
}
}

fun main(args: Array<String>) {
Person.callMe()
}


You may relate companion objects with static methods in Java.


-------------------------------------------------------------------------------------------------------------------------

watch : Click here


Multithreading with Threads & Coroutines


Use "thread" keyword to define a certain block to run on background thread.


import kotlin.concurrent.thread

fun main(args: Array<String>) {

//The program will wait for the background threads to
// Complete their work , until its completely finished

println("Process Started : ${Thread.currentThread().name}")

thread {
println("Background process started : ${Thread.currentThread().name}")
Thread.sleep(3000)
println("Background process ended : ${Thread.currentThread().name}")

}

println("Process Ended : ${Thread.currentThread().name}")
}


// Output
//Process Started : main
//Process Ended : main
//Background process started : Thread-0
//Background process ended : Thread-0


-------------------------------------------------------------------------------------------------------------------------


THREADS


The simplest way to create a Background thread is to use the "thread" block .

This creates a background thread in the application .

The application waits for all the background threads to complete their tasks , only then it closes.



import kotlin.concurrent.thread

fun main(){

run()
}

fun run(){
print("Starting work on back....\n")
thread{
Thread.sleep(5000)
print(Thread.currentThread().name)
}
print("Ending work on back....\n")
}


Threads are memory expensive , hence we use coroutines.

A coroutine is not a thread but a single thread , which contain multiple courotine.

You can create many (even millions ) of coroutines , since they are not memory expensive.


--------------------------------------------------------------------------------------------------------------------------

Watch: Click here


COROUTINES :


Add Depedency to use Coroutines :

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"


There are mainly 2 ways to create a coroutine in Kotlin :

1] use GlobalScope.launch{ }

2] use runBlocking{ } - mostly used just in testing.



Create a Coroutine

By default , the program dont stop for the background task to complete unlike "thread".

To stop the program like in "thread" create a suspending function.


import kotlinx.coroutines.*

fun main(args: Array<String>) {

// Unlike Threads , if you use coroutines
// The program will not wait for any task
// going in the background

println("Process Started : ${Thread.currentThread().name}")

GlobalScope.launch{

println("Background process started : ${Thread.currentThread().name}")
Thread.sleep(3000)
println("Background process ended : ${Thread.currentThread().name}")

}

println("Process Ended : ${Thread.currentThread().name}")
}

// Output
//Process Started : main
//Process Ended : main


So you need to make the main thread stop , so that all the background threads can complete their tasks.


import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlin.concurrent.thread

fun main() {

run()
}

fun run() {
print("Starting work on back....\n")
GlobalScope.launch {
Thread.sleep(5000)
print(Thread.currentThread().name + "\n")
}

// In Real world we use a "suspending function"
// since we never know how much time the
// background thread will take to complete the task
Thread.sleep(6000)
print("Ending work on back....\n")
}


-------------------------------------------------------------------------------------------------------------------------


Thread.sleep() & delay() are completely different.

Thread.sleep() - Blocks/Stops the Entire Thread.

Delay() - Block/Stops only the specific coroutine & dont stop other coroutines on the same thread.


When you use delay() , it "Frees" , the particular coroutine, once the delay() completes , a new coroutine or the same coroutine can carry on from there.


Any function with a "suspend" modifier is a suspending function, 

suspending functions can only be called from inside a coroutine.


Delay() is a Suspending Function i.e You cant call it outside of a Coroutine.



Suspending Function ("Suspend" keyword) : 

You can still call a Suspending function by wrapping it inside of a runBlocking{}.

runBlocking{} - blocks the thread in which it is called & creates a coroutine and then runs the code inside it.




// custom suspend function
suspend fun mySuspendFunc(){
delay(2000)
}


----------------------------------------------------------------------------------------------------------------------


COROUTINES BUILDERS


Coroutine builders are functions using which we create coroutines.

Most used Builders to create a coroutine are : 

1] launch 

2] async

3] runBlocking



launch{ }


"GlobalScope" launches the coroutines Globally throughout the app.


"launch{}" inherits the thread of its parent block & runs the coroutine under that thread.


launch{} returns  a JOB object , using this job object , you can cancel or wait for the coroutine .


import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {

// creates a coroutine under
// the main thread.
runBlocking {


print("Starting work....\n")
print(Thread.currentThread().name + "\n")

// Inherits the thread of its parent block
// and runs a coroutine under it.
launch {

delay(2000)
print("Doing work inside LAUNCH....\n")
print(Thread.currentThread().name + "\n")

}

delay(3000)
print("Ending work....\n")
print(Thread.currentThread().name + "\n")

}


}

//Output
//Starting work....
//main
//Doing work inside LAUNCH....
//main
//Ending work....
//main


launch.join( )


import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {

runBlocking {


print("Starting work....\n")
print(Thread.currentThread().name + "\n")


val myJob : Job = launch {

delay(2000)
print("Doing work inside LAUNCH....\n")
print(Thread.currentThread().name + "\n")

}

// waits for the launch{} to complete its task
// No need to hard code the delay function now.
myJob.join()

print("Ending work....\n")
print(Thread.currentThread().name + "\n")

}


}

//Output
//Starting work....
//main
//Doing work inside LAUNCH....
//main
//Ending work....
//main


async{ }


"async" is similar to "launch" main difference is that it returns a object of DEFFERED class , which is a subclass of JOB class.

It has a await() function , which is useful if you want to retrieve some value from the coroutine.



import kotlinx.coroutines.*

fun main(): String {

runBlocking {


print("Starting work....\n")
print(Thread.currentThread().name + "\n")


// Deferred is a sub-class of JOB
// It is a generic class & should contain
// the return type of the async block
// In this case its nothing so "unit"
val myDefferedJob : Deferred<Unit> = async {

delay(2000)
print("Doing work inside LAUNCH....\n")
print(Thread.currentThread().name + "\n")

}

// use await() , if you want to retrieve the last value
myDefferedJob.join()

print("Ending work....\n")
print(Thread.currentThread().name + "\n")

}


}



await( ) 


import kotlinx.coroutines.*

fun main() {

runBlocking {


print("Starting work....\n")
print(Thread.currentThread().name + "\n")


val myDefferedJob : Deferred<String> = async {

delay(2000)
print("Doing work inside LAUNCH....\n")
print(Thread.currentThread().name + "\n")

"Work done"
}

// retrieves the value of last expression inside the block
val resultvalue:String= myDefferedJob.await()

print("Ending work....\n")
print("RESULT : $resultvalue \n")
print(Thread.currentThread().name + "\n")

}


}


---------------------------------------------------------------------------------------------------------------------

Watch: Click here 


COROUTINES CANCELLATION 


To cancel a coroutine , it should be co-operative.





Making a coroutine co-operative


1]  Using suspending functions from "kotlinx.coroutines" package.

If you use anyone of the suspending function from the package , your code becomes co-operative & then if you use .cancel() , your coroutine will be cancelled.


(if you try to cancel the coroutine , incase your code doesnt contain any suspending functiion from the kotlinx.coroutines package , the coroutine will  not be cancelled.)



import kotlinx.coroutines.*

fun main() {

runBlocking {


print("Starting work....\n")
print(Thread.currentThread().name + "\n")


val myjob : Job = launch {

for (i in 1..500){
print("$i ,")

// if you use Thread.sleep() here
// Your code will not be cancelled.
delay(50)
}
print("\n")
}

delay(200)

// You can use cancelAndJoin() instead of 2 seperate func
myjob.cancel()
myjob.join()

print(Thread.currentThread().name + "\n")

}


}


2]  Explicitly check for the cancellation of the coroutine using the CoroutineScope.isActive flag


We dont have such boolean value for THREADS , this is available only for Coroutines.



import kotlinx.coroutines.*

fun main() {

runBlocking {


print("Starting work....\n")
print(Thread.currentThread().name + "\n")


val myjob : Job = launch {

for (i in 1..500){

// if the coroutine is not active it'll
// get out of the loop
if (!isActive){
break
}

print("$i ,")
delay(1)
}
}

delay(200)


myjob.cancel()
myjob.join()

print("\n")
print(Thread.currentThread().name + "\n")

}


}


--------------------------------------------------------------------------------------------------------------------------


COROUTINES TIMEOUTS


Used when you want a coroutine to finish a task under given time.

Kotlin provides us with 2 functions for this :




1] withTimeout( time )  

This function creates a new coroutine & executes the code on that coroutine . 

If the coroutine fails to do the task in the given time , then the function throws a Exception.


import kotlinx.coroutines.*

fun main() {

runBlocking {

print("Main program starts : " + Thread.currentThread().name)

// This code throws a TimeoutCancellationException,
// since the coroutine fails to complete task in given time.

withTimeout(2000) {

for (i in 0..100) {
print(" $i ")
delay(100)
}
}
print("Main program ends : " + Thread.currentThread().name)
}
}


import kotlinx.coroutines.*

fun main() {

runBlocking {


try {
withTimeout(2000) {

for (i in 0..100) {
print(" $i ")
delay(100)
}
}
}catch (e:TimeoutCancellationException){
print("\n")
print("TIMEOUT !")
}
}
}


2] withTimeoutOrNull( time )  


This function creates a new coroutine & executes the code on that coroutine . 

If the coroutine fails to do the task in the given time , then it returns "NULL" value & doesnt throw a exception

You can also retrieve the value from the coroutine. It returns the value of the last expression.


import kotlinx.coroutines.*

fun main() {

runBlocking {

print(" Program started ! \n")

val result:String? = withTimeoutOrNull(2000){
for (i in 0..100){
print(" $i ")
delay(200)
}

// returns this if sucessful or NULL
"WORK DONE"
}

print("\n RESULT : $result")
print("\n Program ended !")

}
}

// OUTPUT
// Program started !
// 0 1 2 3 4 5 6 7 8 9
// RESULT : null
// Program ended !


----------------------------------------------------------------------------------------------------------------------------


Java and Kotlin code is completely interpolable:

(Linkedlist.java)

public class Linkedlist {

Node head;

static class Node {

int data;
Node next;

Node(int data) {
this.data = data;
this.next = null;
}

}

void add_node(int data) {

Node newNode = new Node(data);

if (head == null) {
head = newNode;
newNode.next = null;
} else {

Node temp = head;

while (temp.next != null) {
temp = temp.next;
}
temp.next = newNode;
newNode.next = null;
}

}

void print_all() {

if (head != null) {

Node temp = head;
while (temp != null) {
System.out.println(temp.data);
temp = temp.next;
}

}

}


(MyMain.kt)


fun main(args:Array<String>){


val linky = Linkedlist()
linky.add_node(101)
linky.add_node(103)
linky.add_node(102)
linky.print_all()

}


----------------------------------------------------------------------------------------------------------------------------




























































































































Comments

Popular posts from this blog

React Js + React-Redux (part-2)

React Js + CSS Styling + React Router (part-1)

ViteJS (Module Bundlers, Build Tools)