├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── kotlinc.xml ├── libraries │ └── KotlinJavaRuntime.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── vcs.xml ├── KotlinTutorials.iml ├── README.md └── src ├── 01_hello_world.kt ├── 02_explore_first_app.kt ├── 03_comments.kt ├── 04_variables_data_types.kt ├── 05_kotlin_basics.kt ├── 06_Person.kt ├── 06_kotlin_basics.kt ├── 07_data_types.kt ├── 08_string_interpolation.kt ├── 09_ranges.kt ├── 10_default_functions.kt ├── 10_if_expression.kt ├── 11_when_expression.kt ├── 12_for_loop.kt ├── 13_while_loop.kt ├── 14_do_while.kt ├── 15_break_keyword.kt ├── 16_continue_keyword.kt ├── 17_functions_basics.kt ├── 18_functions_as_expressions.kt ├── 21_named_parameters.kt ├── 22_extension_function_one.kt ├── 23_extension_function_two.kt ├── 24_infix_function.kt ├── 25_tailrec_function.kt ├── 26_class_and_constructor.kt ├── 27_inheritance.kt ├── 28_overriding_methods_properties.kt ├── 29_inheritance_primary_secondary_constructor.kt ├── 30_abstract_class.kt ├── 31_interface.kt ├── 32_data_class.kt ├── 33_object_declaration.kt ├── 34_1_enum_class ├── 34_2_sealed_class.kt ├── 34_companion_object.kt ├── 35_lambdas_higher_order_functions.kt ├── 36_lambdas_example_two.kt ├── 37_lambdas_closures.kt ├── 38_it_keyword_lambdas.kt ├── 39_with_apply_functions.kt ├── 40_arrays.kt ├── 41_list.kt ├── 42_map_hashmap.kt ├── 43_set_hashset.kt ├── 44_filter_map_sorting.kt ├── 45_predicate.kt ├── 46_null_safety.kt ├── 47_lateinit_keyword.kt ├── 48_lazy_keyword.kt ├── 49_with_scope_function.kt ├── 50_apply_scope_function.kt ├── 51_also_scope_function.kt ├── 52_let_scope_function.kt ├── 53_run_scope_function.kt ├── 60_thread_example.kt ├── 61_first_coroutine.kt ├── 62_runBlocking_and_delay.kt ├── 63_custom_suspending_function.kt ├── 64_launch_coroutine_builder.kt ├── 65_async_coroutine_builder.kt ├── 66_a_runBlocking_coroutine_builder.kt ├── 66_b_test_case.kt ├── 68_cooperative_coroutine_suspend_function.kt ├── 69_isActive_flag_cooperative_coroutine.kt ├── 70_exception_handling.kt ├── 71_withContext_coroutine_builder.kt ├── 72_withTimeout_coroutine_builder.kt ├── 73_withTimeoutOrNull_coroutine_builder.kt ├── 74_sequential_suspending_functions.kt ├── 75_concurrency_within_coroutine.kt ├── 76_lazy_async.kt ├── 77_CoroutineScope.kt ├── 78_CoroutineContext_and_Dispatchers.kt ├── MyJavaFile.java └── myKotlinInteroperability.kt /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /.idea/libraries/KotlinJavaRuntime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /KotlinTutorials.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kotlin Programming Tutorial for Beginners 2 | Learn Kotlin Programming, its basics and Fundamentals from scratch. 3 | 4 | ## Topics to be covered 5 | 0. Overview 6 | - Course introduction, prequisites and software required 7 | 1. Installation 8 | - Install required softwares for Windows, MAC and Linux ( Ubuntu ) 9 | 2. Getting Started with Kotlin Programming 10 | - Run your first app in Kotlin 11 | 3. Exploring Data Types and Variables 12 | - Data Types and Variables 13 | - String, Literals and String Interpolation 14 | - Comments 15 | 4. Constants, Variables and Data Types 16 | 5. Control Flow Statements 17 | - IF ELSE 18 | - IF Expressions 19 | - WHEN Expressions 20 | 6. Loop Control Statements 21 | - What are Iterators? 22 | - FOR Loop and how it works 23 | - WHILE Loop 24 | - DO WHILE Loop 25 | - BREAK statements 26 | - CONTINUE keyword 27 | - Labelled FOR Loop 28 | 7. Functions and Interoperability 29 | - Declaring functions 30 | - Interoperability with Java code 31 | - Function as Expressions 32 | - Extension Functions 33 | - Infix Functions 34 | - Default Parameters 35 | - Named Parameters 36 | - Tailrec Functions 37 | 8. Object Oriented Programming in Kotlin 38 | - Defining Class and creating Objects 39 | - INIT block 40 | - Primary and Secondary Constructors 41 | - Properties ( Field variables ) 42 | - Inheritance 43 | - Method and Property Overriding 44 | - Polymorphism 45 | - Abstract Class, Property and Method 46 | - Interface 47 | - Data Class 48 | - Object Declaration 49 | - Enum class 50 | - Sealed class 51 | - Companion Object 52 | 9. Functional Programming in Koltin 53 | - Lambdas 54 | - Higher-Order Functions 55 | - Closures 56 | - 'it' keyword 57 | - 'with' function 58 | - 'apply' function 59 | 10. Collections in Kotlin 60 | - Arrays 61 | - List 62 | - Map and HashMap 63 | - Set and HashSet 64 | 11. Sorting and Filtering 65 | - "filter" function 66 | - "map" function 67 | - Predicates: all, any, find, count. 68 | 12. Kotlin NULL Safety 69 | - Safe call 70 | - with Let 71 | - Elvis 72 | - Lateinit keyword 73 | - Lazy delegation and 'lateinit' vs. 'lazy' 74 | 13. Scope Functions 75 | - with 76 | - apply 77 | - let 78 | - also 79 | - run 80 | 14. Coroutines 81 | - What are Coroutines? How are they related to Threads? 82 | - launch, async, runBlocking, withContext, withTimeoutOrNull, 83 | - Suspending function 84 | - Cancellation and Timeouts 85 | - Cooperative suspending functions and isActive flag 86 | - Exception Handling in Coroutines 87 | - Sequential execution of suspending function in Coroutines 88 | - Concurrency within Coroutine 89 | - lazy 'async' 90 | - CoroutineScope and CoroutineContext 91 | - Dispacthers: Confined dispatcher, Default Dispatcher, and Unconfined Displatcher 92 | 15. Conclusion 93 | 94 | ## Authors 95 | 96 | * **Sriyank Siddhartha** 97 | -------------------------------------------------------------------------------- /src/01_hello_world.kt: -------------------------------------------------------------------------------- 1 | 2 | // Hello World App 3 | 4 | fun main(args: Array) { 5 | print("Hello World") 6 | } 7 | -------------------------------------------------------------------------------- /src/02_explore_first_app.kt: -------------------------------------------------------------------------------- 1 | 2 | // Explore First App 3 | 4 | fun main(args: Array) { 5 | 6 | println("Hello World") 7 | 8 | println(10) 9 | 10 | println(true) 11 | 12 | println(10 / 2) 13 | 14 | println(94.2f) 15 | 16 | println(9 - 3) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/03_comments.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /* 5 | * This is comment line 1 6 | * 7 | * This is comment line 2 8 | * 9 | * This is main function. Entry point of the application. 10 | * */ 11 | 12 | fun main(args: Array) { // This is inline comment ... 13 | print("Hello World") 14 | } 15 | -------------------------------------------------------------------------------- /src/04_variables_data_types.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This is main function. Entry point of the application. 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var myNumber = 10 // Int 8 | var myDecimal = 1.0 // Float 9 | var isActive = true // Boolean 10 | 11 | var myString: String // Mutable String 12 | myString = "Hello World" 13 | myString = "Another World" 14 | 15 | val myAnotherString = "My constant string value" // Immutable String 16 | // myAnotherString = "some value" // NOT ALLOWED, since it is immutable 17 | 18 | print(myNumber) 19 | } 20 | -------------------------------------------------------------------------------- /src/05_kotlin_basics.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * This is main function. Entry point of the application. 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var personObj = Person() 9 | personObj.name = "Steve" 10 | 11 | print("The name of the person is ${personObj.name}") 12 | } 13 | 14 | class Person { 15 | 16 | var name: String = "" 17 | } 18 | -------------------------------------------------------------------------------- /src/06_Person.kt: -------------------------------------------------------------------------------- 1 | 2 | class Persson(var name: String ) { 3 | 4 | fun display() { 5 | print("The name of the person is ${name}") 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/06_kotlin_basics.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This is main function. Entry point of the application. 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var personObj = Persson("Steve") 8 | 9 | personObj.display() 10 | } 11 | -------------------------------------------------------------------------------- /src/07_data_types.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Explore Data Types in Kotlin 4 | * */ 5 | 6 | fun main(args: Array) { 7 | 8 | var name: String 9 | name = "Kevin" 10 | 11 | var age: Int = 10 12 | var myAge = 10 13 | 14 | var isAlive: Boolean = true 15 | var marks: Float = 97.4F 16 | var percentage: Double = 90.78 17 | var gender: Char = 'M' 18 | 19 | print(marks) 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/08_string_interpolation.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Explore String Interpolation in Kotlin 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var rect = Rectangle() 8 | rect.length = 5 9 | rect.breadth = 3 10 | 11 | print("The length of the rectangle is ${rect.length} and breadth is ${rect.breadth}. The area is ${rect.length * rect.breadth}") 12 | 13 | } 14 | 15 | class Rectangle { 16 | 17 | var length: Int = 0 18 | var breadth: Int = 0 19 | } 20 | -------------------------------------------------------------------------------- /src/09_ranges.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * Explore Ranges 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var r1 = 1..5 9 | // This range contains number 1, 2, 3, 4, 5 10 | 11 | val r2 = 5 downTo 1 12 | // This range contains number 5, 4, 3, 2, 1 13 | 14 | val r3 = 5 downTo 1 step 2 15 | // This range contains number 5, 3, 1 16 | 17 | val r4 = 'a'..'z' 18 | // This range contains the values from "a", "b", "c" . . . "z" 19 | 20 | var isPresent = 'c' in r4 21 | 22 | var countDown = 10.downTo(1) 23 | // This range contains number 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 24 | 25 | var moveUp = 1.rangeTo(10) 26 | // This range contains number 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/10_default_functions.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Default Functions 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var result = findVolume(2, 3) 8 | print(result) 9 | } 10 | 11 | fun findVolume(length: Int, breadth: Int, height: Int = 10): Int { 12 | 13 | return length * breadth * height 14 | } 15 | -------------------------------------------------------------------------------- /src/10_if_expression.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * IF as Expression 4 | * */ 5 | fun main(args: Array) { 6 | 7 | val a = 2 8 | 9 | val b = 5 10 | 11 | var maxValue: Int = if (a > b) { 12 | print("a is greater") 13 | a 14 | } else { 15 | print("b is greater") 16 | b 17 | } 18 | 19 | println(maxValue) 20 | } 21 | -------------------------------------------------------------------------------- /src/11_when_expression.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * WHEN as Expression 5 | * */ 6 | fun main(args: Array) { 7 | 8 | val x = 100 9 | 10 | val str: String = when (x) { 11 | 12 | 1 -> "x is 1" 13 | 2 -> "x is 2" 14 | else -> { 15 | "x value is unknown" 16 | "x is an alien" 17 | } 18 | } 19 | 20 | println(str) 21 | } 22 | -------------------------------------------------------------------------------- /src/12_for_loop.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * FOR Loop 5 | * */ 6 | fun main(args: Array) { 7 | 8 | for (i in 1..10) { 9 | 10 | if (i % 2 == 0) { 11 | println(i) 12 | } 13 | } 14 | 15 | println() 16 | 17 | for (i in 10 downTo 0) { 18 | 19 | if (i % 2 == 0) { 20 | println(i) 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/13_while_loop.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * WHILE Loop 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var i = 0 9 | while (i <= 10) { 10 | if (i % 2 == 0) { 11 | println(i) 12 | } 13 | i++ 14 | } 15 | 16 | println() 17 | 18 | var j = 10 19 | while (j >= 0) { 20 | if (j % 2 == 0) { 21 | println(j) 22 | } 23 | j-- 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/14_do_while.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * DO WHILE Loop 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var i = 0 9 | 10 | do { 11 | if (i % 2 == 0) { 12 | println(i) 13 | } 14 | i++ 15 | } while (i <= 10) 16 | 17 | println() 18 | 19 | var j = 10 20 | 21 | do { 22 | if (j % 2 == 0) { 23 | println(j) 24 | } 25 | j-- 26 | } while (j >= 0) 27 | } 28 | -------------------------------------------------------------------------------- /src/15_break_keyword.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * BREAK Keyword and Labelled FOR Loop 5 | * */ 6 | fun main(args: Array) { 7 | 8 | for (i in 0..4) { 9 | println(i) 10 | 11 | if (i == 2) { 12 | break 13 | } 14 | } 15 | 16 | println() 17 | 18 | myLoop@ for (i in 1..3) { 19 | for (j in 1..3) { 20 | println("$i $j") 21 | if (i == 2 && j == 2) 22 | break@myLoop 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/16_continue_keyword.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * CONTINUE Keyword and Labelled FOR Loop 5 | * */ 6 | fun main(args: Array) { 7 | 8 | for (i in 1..3) { 9 | if (i == 2) 10 | continue 11 | println(i) 12 | } 13 | 14 | 15 | myLoop@ for (i in 1..3) { 16 | for (j in 1..3) { 17 | if (i == 2 && j == 2) { 18 | continue@myLoop 19 | } 20 | println("$i $j") 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/17_functions_basics.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * FUNCTIONS Basics 4 | * */ 5 | fun main(args: Array) { 6 | 7 | 8 | var sum = add(2, 4) 9 | 10 | println("Sum is " + sum) 11 | } 12 | 13 | fun add(a: Int, b: Int): Int { 14 | return a + b 15 | } 16 | -------------------------------------------------------------------------------- /src/18_functions_as_expressions.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * FUNCTIONS as Expressions 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var largeValue = max(4, 6) 9 | 10 | println("The greater number is $largeValue") 11 | } 12 | 13 | fun max(a: Int, b: Int): Int 14 | = if (a > b) { 15 | println("$a is greater") 16 | a 17 | } else { 18 | println("$b is greater") 19 | b 20 | } 21 | -------------------------------------------------------------------------------- /src/21_named_parameters.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * Named Parameters 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var result = findTheVolume(breadth = 2, length = 3) 9 | print(result) 10 | } 11 | 12 | fun findTheVolume(length: Int, breadth: Int, height: Int = 10): Int { 13 | 14 | return length * breadth * height 15 | } 16 | -------------------------------------------------------------------------------- /src/22_extension_function_one.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Extension Functions: EXAMPLE ONE 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var student = Studentt() 8 | println("Pass status: " + student.hasPassed(57)) 9 | 10 | println("Scholarship Status: " + student.isScholar(57)) 11 | } 12 | 13 | fun Studentt.isScholar(marks: Int): Boolean { 14 | return marks > 95 15 | } 16 | 17 | class Studentt { // OUR OWN CLASS 18 | 19 | fun hasPassed(marks: Int): Boolean { 20 | return marks > 40 21 | } 22 | } -------------------------------------------------------------------------------- /src/23_extension_function_two.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Extension Functions: EXAMPLE TWO 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var str1: String = "Hello " 8 | var str2: String = "World" 9 | 10 | var str3: String = "Hey " 11 | 12 | println(str3.add(str1, str2)) 13 | 14 | val x: Int = 6 15 | val y: Int = 10 16 | 17 | val greaterVal = x.greaterValue(y) 18 | 19 | println(greaterVal) 20 | } 21 | 22 | fun String.add(s1: String, s2: String): String { 23 | 24 | return this + s1 + s2 25 | } 26 | 27 | fun Int.greaterValue(other: Int): Int { 28 | 29 | if (this > other) 30 | return this 31 | else 32 | return other 33 | } 34 | -------------------------------------------------------------------------------- /src/24_infix_function.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * INFIX FUNCTIONS 4 | * */ 5 | fun main(args: Array) { 6 | 7 | val x: Int = 6 8 | val y: Int = 10 9 | 10 | val greaterVal = x findGreaterValue y // x.findGreaterValue(y) 11 | 12 | println(greaterVal) 13 | } 14 | 15 | infix fun Int.findGreaterValue(other: Int): Int { // INFIX and Extension Func 16 | 17 | if (this > other) 18 | return this 19 | else 20 | return other 21 | } 22 | 23 | /* 24 | * 1. All INFIX Functions are Extension functions 25 | * But all Extension functions are not INFIX 26 | * 2. INFIX Functions just have ONE PARAMETER 27 | * */ 28 | -------------------------------------------------------------------------------- /src/25_tailrec_function.kt: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger 2 | 3 | /* 4 | * Tailrec Function : Recursive Functions 5 | * -> Prevents Stackoverflow Exception 6 | * 7 | * Fibonacci Series 8 | * 0 1 1 2 3 5 8 13 21 ...... 9 | * */ 10 | fun main(args: Array) { 11 | 12 | println(getFibonacciNumber(10000, BigInteger("1"), BigInteger("0"))) 13 | } 14 | 15 | tailrec fun getFibonacciNumber(n: Int, a: BigInteger, b: BigInteger): BigInteger { 16 | 17 | if (n == 0) 18 | return b 19 | else 20 | return getFibonacciNumber(n - 1, a + b, a) 21 | } 22 | -------------------------------------------------------------------------------- /src/26_class_and_constructor.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Class, Primary Constructor, Secondary Constructor and Init Block 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var student = Student("Steve", 10) 8 | 9 | println(student.id) 10 | } 11 | 12 | class Student(var name: String) { 13 | 14 | var id: Int = -1 15 | 16 | init { 17 | println("Student has got a name as $name and id is $id") 18 | } 19 | 20 | constructor(n: String, id: Int): this(n) { 21 | // The body of the secondary constructor is called after init block 22 | this.id = id 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/27_inheritance.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Inheritance 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var dog = Dog() 8 | dog.bread = "labra" 9 | dog.color = "black" 10 | dog.bark() 11 | dog.eat() 12 | 13 | var cat = Cat() 14 | cat.age = 7 15 | cat.color = "brown" 16 | cat.meow() 17 | cat.eat() 18 | 19 | var animal = Animal() 20 | animal.color = "white" 21 | animal.eat() 22 | } 23 | 24 | open class Animal { // Super class / Parent class / Base class 25 | 26 | var color: String = "" 27 | 28 | fun eat() { 29 | println("Eat") 30 | } 31 | } 32 | 33 | class Dog : Animal() { // Sub class / Child class / Derived class 34 | 35 | var bread: String = "" 36 | 37 | fun bark() { 38 | println("Bark") 39 | } 40 | } 41 | 42 | class Cat : Animal() { // Sub class / Child class / Derived class 43 | 44 | var age: Int = -1 45 | 46 | fun meow() { 47 | println("Meow") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/28_overriding_methods_properties.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. Method Overriding 4 | * 2. Property Overriding 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var dog = MyDog() 9 | 10 | println(dog.color) 11 | 12 | dog.eat() 13 | } 14 | 15 | open class MyAnimal { 16 | 17 | open var color: String = "White" 18 | 19 | open fun eat() { 20 | println("Animal Eating") 21 | } 22 | } 23 | 24 | class MyDog : MyAnimal() { 25 | 26 | var bread: String = "" 27 | 28 | override var color: String = "Black" 29 | 30 | fun bark() { 31 | println("Bark") 32 | } 33 | 34 | override fun eat() { 35 | super.eat() 36 | println("Dog is eating") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/29_inheritance_primary_secondary_constructor.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Inheritance with Primary and Secondary Constructors 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var dog = TheDog("Black", "Pug") 8 | } 9 | 10 | open class TheAnimal { // Super class / Parent class / Base class 11 | 12 | var color: String = "" 13 | 14 | constructor(color: String) { 15 | this.color = color 16 | println("From Animal: $color") 17 | } 18 | } 19 | 20 | class TheDog : TheAnimal { // Sub class / Child class / Derived class 21 | 22 | var bread: String = "" 23 | 24 | constructor(color: String, breed: String): super(color) { 25 | this.bread = breed 26 | 27 | println("From Dog: $color and $breed") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/30_abstract_class.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Abstract Class 4 | * */ 5 | fun main(args: Array) { 6 | 7 | // var person = MyPerson() // Not allowed. You cannot create instance of abstract class 8 | 9 | var person = Indian() // Allowed. Abstract Super class reference variable 10 | // pointing to child class object. 11 | person.name = "Steve" 12 | person.eat() 13 | person.goToSchool() 14 | } 15 | 16 | abstract class MyPerson { // you cannot create instance of abstract class 17 | 18 | abstract var name: String 19 | 20 | abstract fun eat() // abstract properties are 'open' by default 21 | 22 | open fun getHeight() {} // A 'open' function ready to be overridden 23 | 24 | fun goToSchool() {} // A normal function 25 | } 26 | 27 | class Indian: MyPerson() { 28 | 29 | override var name: String = "dummy_indian_name" 30 | 31 | override fun eat() { 32 | // Our own code 33 | } 34 | } -------------------------------------------------------------------------------- /src/31_interface.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * INTERFACE 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var myButton = MyButton() 8 | myButton.onTouch() 9 | myButton.onClick() 10 | } 11 | 12 | interface MyInterfaceListener { // You cannot create the instance of interface 13 | 14 | fun onTouch() // Methods in interface are abstract by default 15 | 16 | fun onClick() { // Normal methods are public and open by default but NOT FINAL 17 | println("MyInterfaceListener: onClick") 18 | } 19 | } 20 | 21 | interface MySecondInterface { // You cannot create the instance of interface 22 | 23 | fun onTouch() { // Normal Method 24 | println("MySecondInterface: onTouch") 25 | } 26 | 27 | fun onClick() { // Normal methods are public and open by default but NOT FINAL 28 | println("MySecondInterface: onClick") 29 | } 30 | 31 | } 32 | 33 | class MyButton: MyInterfaceListener, MySecondInterface { 34 | 35 | override fun onTouch() { 36 | super.onClick() 37 | super.onClick() 38 | } 39 | 40 | override fun onClick() { 41 | super.onTouch() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/32_data_class.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Data Class 4 | * */ 5 | fun main(args: Array) { 6 | 7 | var user1 = User("Sam", 10) 8 | 9 | var user2 = User("Sam", 10) 10 | 11 | println(user1.toString()) 12 | 13 | if (user1 == user2) 14 | println("Equal") 15 | else 16 | println("Not equal") 17 | 18 | var newUser = user1.copy(id = 25) 19 | println(newUser) 20 | } 21 | 22 | data class User(var name: String, var id: Int) 23 | -------------------------------------------------------------------------------- /src/33_object_declaration.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. Object Declaration 4 | * */ 5 | fun main(args: Array) { 6 | 7 | CustomersData.count = 98 8 | CustomersData.typeOfCustomers() 9 | 10 | println(CustomersData.typeOfCustomers()) 11 | 12 | CustomersData.count = 109 13 | println(CustomersData.count) 14 | 15 | CustomersData.myMethod("hello") 16 | } 17 | 18 | open class MySuperClass { 19 | 20 | open fun myMethod(str: String) { 21 | println("MySuperClass") 22 | } 23 | } 24 | 25 | object CustomersData: MySuperClass() { // Object Declaration 26 | 27 | var count: Int = -1 // Behaves like a STATIC variable 28 | 29 | fun typeOfCustomers(): String { // Behaves like a STATIC method 30 | return "Indian" 31 | } 32 | 33 | override fun myMethod(str: String) { // Currently, behaving like a STATIC method 34 | super.myMethod(str) 35 | println("object Customer Data: $str") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/34_1_enum_class: -------------------------------------------------------------------------------- 1 | 2 | interface ICardCashBack { 3 | fun getCashbackValue(): Float 4 | } 5 | 6 | enum class CreditCardType(val color: String, val maxLimit: Int = 1000000): ICardCashBack { 7 | SILVER("gray", 50000) { 8 | override fun getCashbackValue(): Float = 0.02f 9 | }, 10 | GOLD("gold"){ 11 | override fun getCashbackValue(): Float = 0.04f 12 | }, 13 | PLATINUM("black"){ 14 | override fun getCashbackValue(): Float = 0.06f 15 | } 16 | } 17 | 18 | 19 | fun main() { 20 | 21 | /* Access properties and methods */ 22 | println(CreditCardType.SILVER.color) // gray 23 | println(CreditCardType.SILVER.getCashbackValue()) // 0.02 24 | 25 | /* Enum constants are objects of enum class type. */ 26 | val peterCardType: CreditCardType = CreditCardType.GOLD 27 | 28 | /* Each enum object has two properties: ordinal and name */ 29 | println(CreditCardType.GOLD.ordinal) 30 | println(CreditCardType.GOLD) // OR CreditCardType.GOLD.name 31 | 32 | /* Each enum object has two methods: values() and valueOf() */ 33 | val myConstants: Array = CreditCardType.values() 34 | myConstants.forEach { println(it) } 35 | 36 | /* Using in 'when' statement */ 37 | when(peterCardType) { 38 | CreditCardType.SILVER -> println("Peter has silver card") 39 | CreditCardType.GOLD -> println("Peter has gold card") 40 | CreditCardType.PLATINUM -> println("Peter has platinum card") 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/34_2_sealed_class.kt: -------------------------------------------------------------------------------- 1 | 2 | // Limitations of Enum class is overcome by sealed class. 3 | enum class Color(val colorShade: String) { 4 | RED("light red"), 5 | GREEN("light green"), // These hard-coded values cannot be changed. They are constants. 6 | // BLUE(val myBlueColorShade: String) // variable values are not allowed in enum 7 | } 8 | 9 | sealed class Shape { 10 | data class Circle(var radius: Float): Shape() // subclass can be a data class 11 | class Square(var side: Int): Shape() // subclass can be a regular class 12 | 13 | object NotAShape : Shape() // subclass can be an object (singleton) 14 | 15 | // sealed class Line : Shape() // subclass can be another sealed class 16 | // sealed interface Draw // subclass can be an interface 17 | } 18 | 19 | // You can define any type of subclass outside the sealed class too 20 | class Rectangle(var length: Int, var breadth: Int): Shape() 21 | 22 | 23 | fun main() { 24 | 25 | var circle = Shape.Circle(3.0f) 26 | var square = Shape.Square(8) 27 | var rectangle = Rectangle(20,10) // Slightly different than above two 28 | 29 | val noShape = Shape.NotAShape 30 | 31 | checkShape(noShape) 32 | } 33 | 34 | fun checkShape(shape: Shape) { 35 | 36 | when (shape) { 37 | is Shape.Circle -> println("Circle area is ${3.14 * shape.radius * shape.radius}") 38 | is Shape.Square -> println("Square area is ${shape.side * shape.side}") 39 | is Rectangle -> println("Rectagle area is ${shape.length * shape.breadth}") 40 | Shape.NotAShape -> println("No shape found") // 'is' is not required for object (singleton) 41 | // else -> "else case is not required as all case is covered above" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/34_companion_object.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. Companion Object 4 | * */ 5 | fun main(args: Array) { 6 | 7 | MyClass.count // You can print it and check result 8 | 9 | MyClass.typeOfCustomers() 10 | } 11 | 12 | class MyClass { 13 | 14 | companion object { 15 | 16 | var count: Int = -1 // Behaves like STATIC variable 17 | 18 | @JvmStatic 19 | fun typeOfCustomers(): String { // Behaves like STATIC method 20 | return "Indian" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/35_lambdas_higher_order_functions.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | EXAMPLE ONE 4 | 5 | * 1. Lambda Expression 6 | * 2. Higher-Order Function 7 | * */ 8 | fun main(args: Array) { 9 | 10 | val program = Program() 11 | 12 | program.addTwoNumbers(2, 7) // Simple way... for better understanding 13 | 14 | program.addTwoNumbers(2, 7, object : MyInterface { // Using Interface / OOPs way 15 | 16 | override fun execute(sum: Int) { 17 | println(sum) // Body 18 | } 19 | }) 20 | 21 | val test: String = "Hello" 22 | 23 | val myLambda: (Int) -> Unit = { s: Int -> println(s)} // Lambda Expression [ Function ] 24 | program.addTwoNumbers(2, 7, myLambda) 25 | } 26 | 27 | class Program { 28 | 29 | fun addTwoNumbers(a: Int, b: Int, action: (Int) -> Unit) { // High Level Function with Lambda as Parameter 30 | 31 | val sum = a + b 32 | action(sum) // println(sum) 33 | // println(sum) // Body 34 | } 35 | 36 | fun addTwoNumbers(a: Int, b: Int, action: MyInterface) { // Using Interface / Object Oriented Way 37 | val sum = a + b 38 | action.execute(sum) 39 | } 40 | 41 | fun addTwoNumbers(a: Int, b: Int) { // Simple way.. Just for Better Understanding 42 | 43 | val sum = a + b 44 | println(sum) 45 | } 46 | } 47 | 48 | interface MyInterface { 49 | fun execute(sum: Int) 50 | } 51 | -------------------------------------------------------------------------------- /src/36_lambdas_example_two.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | EXAMPLE TWO 4 | 5 | * 1. Lambda Expression 6 | * 2. Higher-Order Function 7 | * */ 8 | fun main(args: Array) { 9 | 10 | val program = MyProgram() 11 | 12 | // val myLambda: (Int, Int) -> Int = { x, y -> x + y} // Lambda Expression [ Function ] 13 | // OR, 14 | // program.addTwoNumbers(2, 7, { x, y -> x + y }) 15 | // OR, 16 | program.addTwoNumbers(2, 7) {x, y -> x + y} 17 | } 18 | 19 | class MyProgram { 20 | 21 | fun addTwoNumbers(a: Int, b: Int, action: (Int, Int) -> Int) { // High Level Function with Lambda as Parameter 22 | 23 | val result = action(a, b) 24 | println(result) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/37_lambdas_closures.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. Closures 4 | * */ 5 | fun main(args: Array) { 6 | 7 | val program = TheProgram() 8 | 9 | var result = 0 10 | 11 | program.addTwoNumbers(2, 7) {x, y -> result = x + y} 12 | 13 | println(result) 14 | } 15 | 16 | class TheProgram { 17 | 18 | fun addTwoNumbers(a: Int, b: Int, action: (Int, Int) -> Unit) { // High Level Function with Lambda as Parameter 19 | 20 | action(a, b) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/38_it_keyword_lambdas.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * 1. 'it' keyword 5 | * */ 6 | fun main(args: Array) { 7 | 8 | val program = Programs() 9 | program.reverseAndDisplay("hello", { it.reversed() }) 10 | } 11 | 12 | class Programs { 13 | 14 | fun reverseAndDisplay(str: String, myFunc: (String) -> String) { // High Level Function with Lambda as Parameter 15 | 16 | val result = myFunc(str) // it.reversed() ==> str.reversed() ==> "hello".reversed() = "olleh" 17 | println(result) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/39_with_apply_functions.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. 'with' function 4 | * 2. 'apply' function 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var person = Perrson() 9 | 10 | with(person) { 11 | name = "Steve" 12 | age = 23 13 | } 14 | 15 | person.apply { 16 | name = "Steve" 17 | age = 23 18 | }.startRun() 19 | 20 | println(person.name) 21 | println(person.age) 22 | } 23 | 24 | class Perrson { 25 | 26 | var name: String = "" 27 | var age: Int = -1 28 | 29 | fun startRun() { 30 | println("Now I am ready to run") 31 | } 32 | } -------------------------------------------------------------------------------- /src/40_arrays.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. Arrays 4 | * */ 5 | fun main(args: Array) { 6 | 7 | // Elements : 32 0 0 54 0 8 | // Index : 0 1 2 3 4 9 | 10 | var myArray = Array(5) { 0 } // Mutable. Fixed Size. 11 | myArray[0] = 32 12 | myArray[3] = 54 13 | myArray[1] = 11 14 | 15 | for (element in myArray) { // Using individual elements (Objects) 16 | println(element) 17 | } 18 | 19 | println() 20 | 21 | for (index in 0..myArray.size - 1) { 22 | println(myArray[index]) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/41_list.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. List and ArrayList 4 | * */ 5 | fun main(args: Array) { 6 | 7 | // Elements : 8 | // Index : 0 1 2 3 4 9 | 10 | // var list = mutableListOf() // Mutable, No Fixed Size, Can Add or Remove Elements 11 | // var list = arrayListOf() // Mutable, No Fixed Size, Can Add or Remove Elements 12 | var list = ArrayList() // Mutable, No Fixed Size, Can Add or Remove Elements 13 | list.add("Yogi") // 0 14 | list.add("Manmohan") // 1 15 | list.add("Vajpayee") // 2 16 | 17 | // list.remove("Manmohan") 18 | // list.add("Vajpayee") 19 | 20 | list[1] = "Modi" 21 | 22 | for (element in list) { // Using individual elements (Objects) 23 | println(element) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/42_map_hashmap.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. Map and HashMap 4 | * */ 5 | fun main(args: Array) { 6 | 7 | // Map Tutorial: Key-Value pair 8 | // var myMap = HashMap() // Mutable, READ and WRITE both, No Fixed Size 9 | // var myMap = mutableMapOf() // Mutable, READ and WRITE both, No Fixed Size 10 | var myMap = hashMapOf() // Mutable, READ and WRITE both, No Fixed Size 11 | 12 | myMap.put(4, "Yogi") 13 | myMap.put(43, "Manmohan") 14 | myMap.put(7, "Vajpayee") 15 | 16 | myMap.put(43, "Modi") 17 | 18 | for (key in myMap.keys) { 19 | println("Element at $key = ${myMap[key]}") // myMap.get(key) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/43_set_hashset.kt: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 1. Set and HashSet 4 | * */ 5 | fun main(args: Array) { 6 | 7 | // "Set" contains unique elements 8 | // "HashSet" also contains unique elements but sequence is not guaranteed in output 9 | 10 | var mySet = mutableSetOf( 2, 54, 3, 1, 0, 9, 9, 9, 8) // Mutable Set, READ and WRITE both 11 | // var mySet = hashSetOf( 2, 54, 3, 1, 0, 9, 9, 9, 8) // Mutable Set, READ and WRITE both 12 | 13 | mySet.remove(54) 14 | mySet.add(100) 15 | 16 | for (element in mySet) { 17 | println(element) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/44_filter_map_sorting.kt: -------------------------------------------------------------------------------- 1 | /** FILTER 2 | * Returns a list containing only elements matching the given [predicate] 3 | * */ 4 | 5 | /** MAP 6 | * Returns a list containing the results of applying the given [transform] function 7 | * to each element in the original collection 8 | * */ 9 | 10 | fun main(args: Array) { 11 | 12 | val myNumbers: List = listOf(2, 3, 4, 6, 23, 90) 13 | 14 | val mySmallNums = myNumbers.filter { it < 10 } // OR { num -> num < 10 } 15 | for (num in mySmallNums) { 16 | println(num) 17 | } 18 | 19 | val mySquaredNums = myNumbers.map { it * it } // OR { num -> num * num } 20 | for (num in mySquaredNums) { 21 | println(num) 22 | } 23 | 24 | var people = listOf(Pperson(10, "Steve"), Pperson(23, "Annie"), Pperson(17, "Sam")) 25 | var names = people.filter { person ->person.name.startsWith("S") }.map { it.name } 26 | 27 | for (name in names) { 28 | println(name) 29 | } 30 | } 31 | 32 | class Pperson(var age: Int, var name: String) { 33 | // Some other code.. 34 | } 35 | -------------------------------------------------------------------------------- /src/45_predicate.kt: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * PREDICATES 4 | * */ 5 | fun main(args: Array) { 6 | 7 | val myNumbers = listOf(2, 3, 4, 6, 23, 90) 8 | 9 | val myPredicate = { num: Int -> num > 10 } 10 | 11 | val check1 = myNumbers.all( myPredicate ) // Are all elements greater than 10? 12 | println(check1) 13 | 14 | val check2 = myNumbers.any(myPredicate) // Does any of these elements satisfy the predicate? 15 | println(check2) 16 | 17 | val totalCount: Int = myNumbers.count(myPredicate) // Number of elements that satify the predicate. 18 | println(totalCount) 19 | 20 | val num = myNumbers.find(myPredicate) // Returns the first number that matches the predicate 21 | println(num) 22 | } 23 | -------------------------------------------------------------------------------- /src/46_null_safety.kt: -------------------------------------------------------------------------------- 1 | 2 | fun main(args: Array) { 3 | 4 | // WAP to find out length of name 5 | val name: String? = "Steve" // change it to null and see the effect in output 6 | 7 | // 1. Safe Call ( ?. ) 8 | // Returns the length if 'name' is not null else returns NULL 9 | // Use it if you don't mind getting NULL value 10 | println("The length of name is ${name?.length}") 11 | 12 | 13 | // 2. Safe Call with let ( ?.let ) 14 | // It executes the block ONLY IF name is NOT NULL 15 | name?.let { 16 | println("The length of name is ${name.length}") 17 | } 18 | 19 | 20 | // 3. Elvis-operator ( ?: ) 21 | // When we have nullable reference 'name', we can say "is name is not null", use it, 22 | // otherwise use some non-null value" 23 | val len = if (name != null) 24 | name.length 25 | else 26 | -1 27 | 28 | val length = name?.length ?: -1 29 | println("The length of name is ${length}") 30 | 31 | // 4. Non-null assertion operator ( !! ) 32 | // Use it when you are sure the value is NOT NULL 33 | // Throws NullPointerException if the value is found to be NULL 34 | 35 | println("The length of name is ${name!!.length}") 36 | } 37 | -------------------------------------------------------------------------------- /src/47_lateinit_keyword.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | fun main(args: Array) { 4 | 5 | val country = Country() 6 | 7 | // country.name = "India" 8 | // println(country.name) 9 | 10 | country.setup() 11 | } 12 | 13 | class Country { 14 | 15 | lateinit var name: String 16 | 17 | fun setup() { 18 | name = "USA" 19 | println("The name of country is $name") 20 | } 21 | } 22 | 23 | // lateinit used only with mutable data type [ var ] 24 | // lateinit used only with non-nullable data type 25 | // lateinit values must be initialised before you use it 26 | 27 | // If you try to access lateinit variable without initializing it then it throws UninitializedPropertyAccessException 28 | -------------------------------------------------------------------------------- /src/48_lazy_keyword.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | val pi: Float by lazy { 4 | 3.14f 5 | } 6 | 7 | fun main(args: Array) { 8 | 9 | println("Some initial code.....") 10 | 11 | // pi is not initialised yet 12 | 13 | val area1 = pi * 4 * 4 // pi gets initialised and assigned the value of 3.14f for the first time 14 | 15 | val area2 = pi * 9 * 9 // The value pi is loaded from cache memory 16 | 17 | println("Some more code....") 18 | } 19 | 20 | 21 | // ‘lazy initialization’ was designed to prevent unnecessary initialization of objects. 22 | // You variables will not be initialised unless you use it in your code 23 | // It is initialized only once. Next time when you use it, you get the value from cache memory. 24 | 25 | // It is thread safe 26 | // It is initialized in the thread where it is used for the first time. 27 | // Other threads use the same value stored in the cache 28 | 29 | // The variable can be var or val. 30 | // The variable can be nullable or non-nullable 31 | -------------------------------------------------------------------------------- /src/49_with_scope_function.kt: -------------------------------------------------------------------------------- 1 | class Person { 2 | var name: String = "Sriyank Siddhartha" 3 | var age: Int = 26 4 | } 5 | 6 | fun main() { 7 | 8 | /** Scope Function: 'with' 9 | Property 1: Refer to context object by using 'this' 10 | Property 2: The return value is the 'lambda result' */ 11 | 12 | val person = Person() 13 | 14 | val bio: String = with(person) { 15 | println(name) 16 | println(age) 17 | age + 5 18 | "He is a freak who loves to teach in his own way" // will be returned and stored in 'bio' String variable 19 | } 20 | 21 | // println("Age after five years is $ageAfterFiveYears") 22 | println(bio) 23 | } -------------------------------------------------------------------------------- /src/50_apply_scope_function.kt: -------------------------------------------------------------------------------- 1 | class Person { 2 | var name: String = "" 3 | var age: Int = 0 4 | } 5 | 6 | fun main() { 7 | 8 | /** Scope Function: 'apply' 9 | Property 1: Refer to context object by using 'this' 10 | Property 2: The return value is the 'context object' */ 11 | 12 | val person = Person().apply { 13 | name = "Sriyank Siddhartha" 14 | age = 26 15 | } 16 | 17 | with(person) { 18 | println(name) // prints Sriyank Siddhartha 19 | println(age) // prints 26 20 | } 21 | 22 | // Perform some other operations on 'person' object 23 | person.also { 24 | it.name = "Shreks from Smartherd" 25 | println("New name: ${it.name}") // prints New name: Shreks from Smartherd 26 | } 27 | } -------------------------------------------------------------------------------- /src/51_also_scope_function.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | fun main() { 4 | 5 | /** Scope Function: 'also' 'ALSO PERFORM THE FOLLOWING EXTRA OPERATION' 6 | Property 1: Refer to context object by using 'it' 7 | Property 2: The return value is the 'context object' */ 8 | 9 | // Initialise numbersList 10 | val numbersList: MutableList = mutableListOf(1, 2, 3) 11 | 12 | // Some other code... may be a function call or program to swap numbers (doesn't matter what code) 13 | 14 | // Operations on the 'numbersList' 15 | val duplicateNumbers = numbersList.also { 16 | println("The list elements are: $it") 17 | it.add(4) 18 | println("The list elements after adding an element: $it") 19 | it.remove(2) 20 | println("The list elements after removing an element: $it") 21 | } 22 | 23 | // duplicateNumbers will be same as numbersList 24 | println("Original numbers: $numbersList") 25 | println("Duplicate numbers: $duplicateNumbers") 26 | } -------------------------------------------------------------------------------- /src/52_let_scope_function.kt: -------------------------------------------------------------------------------- 1 | 2 | fun main() { 3 | 4 | /** Scope Function: 'let' 5 | Property 1: Refer to context object by using 'it' 6 | Property 2: The return value is the 'lambda result' */ 7 | 8 | // Use 'let' function to avoid NullPointerException 9 | 10 | val name: String? = "Hello" 11 | 12 | // Execute the lambda expression only if the 'name' variable is NOT NULL 13 | val stringLength = name?.let { 14 | println(it.reversed()) 15 | println(it.capitalize()) 16 | it.length // Will be returned and stored within stringLength variable 17 | } 18 | 19 | println(stringLength) 20 | } -------------------------------------------------------------------------------- /src/53_run_scope_function.kt: -------------------------------------------------------------------------------- 1 | 2 | class Person { 3 | var name: String = "Sriyank Siddhartha" 4 | var age: Int = 26 5 | } 6 | 7 | fun main() { 8 | 9 | /** Scope Function: 'run' 10 | Property 1: Refer to context object by using 'this' 11 | Property 2: The return value is the 'lambda result' */ 12 | 13 | // 'run' is combination of 'with' and 'let' 14 | // If you want to operate on a Nullable object and avoid NullPointerException then use 'run' 15 | 16 | val person: Person? = Person() 17 | 18 | val bio = person?.run { 19 | println(name) 20 | println(age) 21 | age + 5 22 | "He is a freak who loves to teach in his own way" // will be returned and stored in 'bio' variable 23 | } 24 | 25 | println(bio) 26 | } -------------------------------------------------------------------------------- /src/60_thread_example.kt: -------------------------------------------------------------------------------- 1 | import kotlin.concurrent.thread 2 | 3 | fun main() { // Executes in main thread 4 | 5 | println("Main program starts: ${Thread.currentThread().name}") 6 | 7 | thread { // creates a background thread (worker thread) 8 | println("Fake work starts: ${Thread.currentThread().name}") 9 | Thread.sleep(1000) // Pretend doing some work... may be file upload 10 | println("Fake work finished: ${Thread.currentThread().name}") 11 | } 12 | 13 | println("Main program ends: ${Thread.currentThread().name}") 14 | } -------------------------------------------------------------------------------- /src/61_first_coroutine.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | 4 | fun main() { // Executes in main thread 5 | 6 | println("Main program starts: ${Thread.currentThread().name}") 7 | 8 | GlobalScope.launch { // creates a background coroutine that runs on a background thread 9 | println("Fake work starts: ${Thread.currentThread().name}") 10 | Thread.sleep(1000) // Pretend doing some work... may be file upload 11 | println("Fake work finished: ${Thread.currentThread().name}") 12 | } 13 | 14 | // Blocks the current main thread & wait for coroutine to finish (practically not a right way to wait) 15 | Thread.sleep(2000) 16 | println("Main program ends: ${Thread.currentThread().name}") 17 | } -------------------------------------------------------------------------------- /src/62_runBlocking_and_delay.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | 4 | fun main() = runBlocking { // Executes in main thread 5 | 6 | println("Main program starts: ${Thread.currentThread().name}") // main thread 7 | 8 | GlobalScope.launch { // Thread: T1 9 | println("Fake work starts: ${Thread.currentThread().name}") // Thread: T1 10 | delay(1000) // Coroutine is suspended but Thread: T1 is free (not blocked) 11 | println("Fake work finished: ${Thread.currentThread().name}") // Either T1 or some other thread. 12 | } 13 | 14 | delay(2000) // main thread: wait for coroutine to finish (practically not a right way to wait) 15 | 16 | println("Main program ends: ${Thread.currentThread().name}") // main thread 17 | } -------------------------------------------------------------------------------- /src/63_custom_suspending_function.kt: -------------------------------------------------------------------------------- 1 | 2 | import kotlinx.coroutines.* 3 | 4 | 5 | fun main() = runBlocking { // Executes in main thread 6 | 7 | println("Main program starts: ${Thread.currentThread().name}") // main thread 8 | 9 | GlobalScope.launch { // Thread: T1 10 | println("Fake work starts: ${Thread.currentThread().name}") // Thread: T1 11 | mySuspendFunc(1000) // Coroutine is suspended but Thread: T1 is free (not blocked) 12 | println("Fake work finished: ${Thread.currentThread().name}") // Either T1 or some other thread. 13 | } 14 | 15 | mySuspendFunc(2000) // main thread: wait for coroutine to finish (practically not a right way to wait) 16 | 17 | println("Main program ends: ${Thread.currentThread().name}") // main thread 18 | } 19 | 20 | suspend fun mySuspendFunc(time: Long) { 21 | // code.. 22 | delay(time) 23 | } -------------------------------------------------------------------------------- /src/64_launch_coroutine_builder.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | 4 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 5 | 6 | println("Main program starts: ${Thread.currentThread().name}") // main thread 7 | 8 | val job: Job = launch { // Thread: main 9 | println("Fake work starts: ${Thread.currentThread().name}") // Thread: main 10 | delay(1000) // Coroutine is suspended but Thread: main is free (not blocked) 11 | println("Fake work finished: ${Thread.currentThread().name}") // Thread: main 12 | } 13 | 14 | job.join() // main thread: wait for coroutine to finish 15 | 16 | println("Main program ends: ${Thread.currentThread().name}") // main thread 17 | } -------------------------------------------------------------------------------- /src/65_async_coroutine_builder.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | 4 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 5 | 6 | println("Main program starts: ${Thread.currentThread().name}") // main thread 7 | 8 | val deferredJob: Deferred = async // Thread: main 9 | println("Fake work starts: ${Thread.currentThread().name}") // Thread: main 10 | delay(1000) // Coroutine is suspended but Thread: main is free (not blocked) 11 | println("Fake work finished: ${Thread.currentThread().name}") // Thread: main 12 | 15 13 | } 14 | 15 | val num: Int = deferredJob.await() // main thread: wait for coroutine to finish and return data 16 | 17 | println("Main program ends: ${Thread.currentThread().name}") // main thread 18 | } -------------------------------------------------------------------------------- /src/66_a_runBlocking_coroutine_builder.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | 4 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 5 | 6 | println("Main program starts: ${Thread.currentThread().name}") // main thread 7 | 8 | val deferredJob: Deferred = async // Thread: main 9 | println("Fake work starts: ${Thread.currentThread().name}") // Thread: main 10 | delay(1000) // Coroutine is suspended but Thread: main is free (not blocked) 11 | println("Fake work finished: ${Thread.currentThread().name}") // Thread: main 12 | 15 13 | } 14 | 15 | val num: Int = deferredJob.await() // main thread: wait for coroutine to finish and return data 16 | 17 | println("Main program ends: ${Thread.currentThread().name}") // main thread 18 | } 19 | 20 | suspend fun myOwnSuspendingFunc() { 21 | delay(1000) // do something 22 | } -------------------------------------------------------------------------------- /src/66_b_test_case.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.runBlocking 2 | import org.junit.Assert 3 | import org.junit.Test 4 | 5 | class SimpleTest { 6 | 7 | @Test 8 | fun myFirstTest() = runBlocking { 9 | myOwnSuspendingFunc() 10 | Assert.assertEquals(10, 5 + 5) 11 | } 12 | } -------------------------------------------------------------------------------- /src/68_cooperative_coroutine_suspend_function.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 4 | 5 | println("Main program starts: ${Thread.currentThread().name}") // main thread 6 | 7 | val job: Job = launch { // Thread main: Creates a non-blocking coroutine 8 | for (i in 0..500) { 9 | print("$i.") 10 | yield() // or use delay() or any other suspending function as per your need. 11 | } 12 | } 13 | 14 | delay(10) // Let's print a few values before we cancel 15 | job.cancelAndJoin() 16 | 17 | println("\nMain program ends: ${Thread.currentThread().name}") // main thread 18 | } 19 | -------------------------------------------------------------------------------- /src/69_isActive_flag_cooperative_coroutine.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 4 | 5 | println("Main program starts: ${Thread.currentThread().name}") // main thread 6 | 7 | val job: Job = launch(Dispatchers.Default) { // Thread T1: Creates a non-blocking coroutine 8 | for (i in 0..500) { 9 | if (!isActive) { 10 | return@launch // break 11 | } 12 | print("$i.") 13 | Thread.sleep(1) 14 | } 15 | } 16 | 17 | delay(10) // Let's print a few values before we cancel 18 | job.cancelAndJoin() 19 | 20 | println("\nMain program ends: ${Thread.currentThread().name}") // main thread 21 | } -------------------------------------------------------------------------------- /src/70_exception_handling.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 4 | 5 | println("Main program starts: ${Thread.currentThread().name}") // main thread 6 | 7 | val job: Job = launch(Dispatchers.Default) { // Thread T1: Creates a non-blocking coroutine 8 | try { 9 | for (i in 0..500) { 10 | print("$i.") 11 | delay(5) // or use yield() or any other suspending function as per your need. 12 | } 13 | } catch (ex: CancellationException) { 14 | print("\nException caught safely: ${ex.message}") 15 | } finally { 16 | print("\nClose resources in finally") 17 | } 18 | } 19 | 20 | delay(10) // Let's print a few values before we cancel 21 | job.cancel(CancellationException("My own crash message")) 22 | job.join() 23 | 24 | println("\nMain program ends: ${Thread.currentThread().name}") // main thread 25 | } -------------------------------------------------------------------------------- /src/71_withContext_coroutine_builder.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 4 | 5 | println("Main program starts: ${Thread.currentThread().name}") // main thread 6 | 7 | val job: Job = launch(Dispatchers.Default) { // Thread T1: Creates a non-blocking coroutine 8 | try { 9 | for (i in 0..500) { 10 | print("$i.") 11 | delay(5) // or use yield() or any other suspending function as per your need. 12 | } 13 | } catch (ex: CancellationException) { 14 | print("\nException caught safely: ${ex.message}") 15 | } finally { 16 | withContext(NonCancellable) { 17 | delay(1000) // Generally we don't use suspending function in finally 18 | print("\nClose resources in finally") 19 | } 20 | } 21 | } 22 | 23 | delay(10) // Let's print a few values before we cancel 24 | job.cancel(CancellationException("My own crash message")) 25 | job.join() 26 | 27 | println("\nMain program ends: ${Thread.currentThread().name}") // main thread 28 | } -------------------------------------------------------------------------------- /src/72_withTimeout_coroutine_builder.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 4 | 5 | println("Main program starts: ${Thread.currentThread().name}") // main thread 6 | 7 | withTimeout(1300) { 8 | try { 9 | for (i in 0..1000) { 10 | print("$i.") 11 | delay(500) 12 | } 13 | } catch (ex: TimeoutCancellationException) { 14 | // .. code.. 15 | } finally { 16 | // .. code.. 17 | } 18 | } 19 | 20 | println("\nMain program ends: ${Thread.currentThread().name}") // main thread 21 | } -------------------------------------------------------------------------------- /src/73_withTimeoutOrNull_coroutine_builder.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 4 | 5 | println("Main program starts: ${Thread.currentThread().name}") // main thread 6 | 7 | val result: String? = withTimeoutOrNull(2000) { 8 | for (i in 0..500) { 9 | print("$i.") 10 | delay(500) 11 | } 12 | 13 | "I am done" 14 | } 15 | 16 | print("Result: $result") 17 | 18 | println("\nMain program ends: ${Thread.currentThread().name}") // main thread 19 | } -------------------------------------------------------------------------------- /src/74_sequential_suspending_functions.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlin.system.measureTimeMillis 3 | 4 | 5 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 6 | 7 | println("Main program starts: ${Thread.currentThread().name}") // main thread 8 | 9 | val time = measureTimeMillis { 10 | val msgOne = getMessageOne() 11 | val msgTwo = getMessageTwo() 12 | println("The entire message is: ${msgOne + msgTwo}") 13 | } 14 | 15 | println("Completed in $time ms") 16 | println("Main program ends: ${Thread.currentThread().name}") // main thread 17 | } 18 | 19 | suspend fun getMessageOne(): String { 20 | delay(1000L) // pretend to do some work 21 | return "Hello " 22 | } 23 | 24 | suspend fun getMessageTwo(): String { 25 | delay(1000L) // pretend to do some work 26 | return "World!" 27 | } -------------------------------------------------------------------------------- /src/75_concurrency_within_coroutine.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | import kotlin.system.measureTimeMillis 3 | 4 | 5 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 6 | 7 | println("Main program starts: ${Thread.currentThread().name}") // main thread 8 | 9 | val time = measureTimeMillis { 10 | val msgOne: Deferred = async { 11 | // ..more code.. 12 | getMessageOne() 13 | } 14 | val msgTwo: Deferred = async { 15 | // ..more code.. 16 | getMessageTwo() 17 | } 18 | println("The entire message is: ${msgOne.await() + msgTwo.await()}") 19 | } 20 | 21 | println("Completed in $time ms") 22 | println("Main program ends: ${Thread.currentThread().name}") // main thread 23 | } 24 | 25 | suspend fun getMessageOne(): String { 26 | delay(1000L) // pretend to do some work 27 | return "Hello " 28 | } 29 | 30 | suspend fun getMessageTwo(): String { 31 | delay(1000L) // pretend to do some work 32 | return "World!" 33 | } -------------------------------------------------------------------------------- /src/76_lazy_async.kt: -------------------------------------------------------------------------------- 1 | 2 | import kotlinx.coroutines.* 3 | 4 | fun main() = runBlocking { // Creates a blocking coroutine that executes in current thread (main) 5 | 6 | println("Main program starts: ${Thread.currentThread().name}") // main thread 7 | 8 | val msgOne: Deferred = async(start = CoroutineStart.LAZY) { getMessageOne() } 9 | val msgTwo: Deferred = async(start = CoroutineStart.LAZY) { getMessageTwo() } 10 | println("The entire message is: ${msgOne.await() + msgTwo.await()}") 11 | 12 | println("Main program ends: ${Thread.currentThread().name}") // main thread 13 | } 14 | 15 | suspend fun getMessageOne(): String { 16 | delay(1000L) // pretend to do some work 17 | println("After working in getMessageOne()") 18 | return "Hello " 19 | } 20 | 21 | suspend fun getMessageTwo(): String { 22 | delay(1000L) // pretend to do some work 23 | println("After working in getMessageTwo()") 24 | return "World!" 25 | } -------------------------------------------------------------------------------- /src/77_CoroutineScope.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { 4 | 5 | println("runBlocking: $this") 6 | 7 | launch { 8 | println("launch: $this") 9 | 10 | launch(coroutineContext) { 11 | println("child launch: $this") 12 | } 13 | } 14 | 15 | async { 16 | println("async: $this") 17 | } 18 | 19 | println("... some other code...") 20 | } -------------------------------------------------------------------------------- /src/78_CoroutineContext_and_Dispatchers.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.* 2 | 3 | fun main() = runBlocking { 4 | 5 | // this: CoroutineScope instance 6 | // coroutineContext: CoroutineContext instance 7 | 8 | /* Without Parameter: CONFINED [CONFINED DISPATCHER] 9 | - Inherits CoroutineContext from immediate parent coroutine. 10 | - Even after delay() or suspending function, it continues to run in the same thread. */ 11 | launch { 12 | println("C1: ${Thread.currentThread().name}") // Thread: main 13 | delay(1000) 14 | println("C1 after delay: ${Thread.currentThread().name}") // Thread: main 15 | } 16 | 17 | /* With parameter: Dispatchers.Default [similar to GlobalScope.launch { } ] 18 | - Gets its own context at Global level. Executes in a separate background thread. 19 | - After delay() or suspending function execution, 20 | it continues to run either in the same thread or some other thread. */ 21 | launch(Dispatchers.Default) { 22 | println("C2: ${Thread.currentThread().name}") // Thread: T1 23 | delay(1000) 24 | println("C2 after delay: ${Thread.currentThread().name}") // Thread: Either T1 or some other thread 25 | } 26 | 27 | /* With parameter: Dispatchers.Unconfined [UNCONFINED DISPATCHER] 28 | - Inherits CoroutineContext from the immediate parent coroutine. 29 | - After delay() or suspending function execution, it continues to run in some other thread. */ 30 | launch(Dispatchers.Unconfined) { 31 | println("C3: ${Thread.currentThread().name}") // Thread: main 32 | delay(1000) 33 | println("C3 after delay: ${Thread.currentThread().name}") // Thread: some other thread T1 34 | } 35 | 36 | launch(coroutineContext) { 37 | println("C4: ${Thread.currentThread().name}") // Thread: main 38 | delay(1000) 39 | println("C4 after delay: ${Thread.currentThread().name}") // Thread: main 40 | } 41 | 42 | println("...Main Program...") 43 | } 44 | -------------------------------------------------------------------------------- /src/MyJavaFile.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * Interoperability Example 5 | * */ 6 | public class MyJavaFile { 7 | 8 | public static void main(String[] args) { 9 | 10 | int sum = MyKotlinInteroperabilityKt.addNumbers(3, 4); 11 | System.out.println("Printing sum from Java file :" + sum); 12 | } 13 | 14 | public static int getArea(int l, int b) { 15 | return l * b; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/myKotlinInteroperability.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | * Interoperability Example 5 | * */ 6 | fun main(args: Array) { 7 | 8 | var area = MyJavaFile.getArea(10, 5) 9 | println("Printing area from Kotlin file: $area") 10 | } 11 | 12 | fun addNumbers(a: Int, b: Int): Int { 13 | return a + b 14 | } 15 | --------------------------------------------------------------------------------